Created
April 4, 2019 04:46
-
-
Save hw0k/58deb27b996aa870728529364bcb6323 to your computer and use it in GitHub Desktop.
Spring Boot를 이용한 회원관리 연습
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.controller; | |
import kr.hs.dgsw.springcrmpractice.domain.Attachment; | |
import kr.hs.dgsw.springcrmpractice.service.AttachService; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.core.io.Resource; | |
import org.springframework.http.ResponseEntity; | |
import org.springframework.web.bind.annotation.*; | |
import org.springframework.web.multipart.MultipartFile; | |
@RestController | |
public class AttachController { | |
private final AttachService attachService; | |
@Autowired | |
public AttachController(AttachService attachService) { | |
this.attachService = attachService; | |
} | |
@PostMapping("/attach") | |
public Attachment attach(@RequestPart MultipartFile file) { | |
return attachService.attach(file); | |
} | |
@GetMapping("/attach/{file:.+}") | |
public ResponseEntity<Resource> serve(@PathVariable String file) { | |
return attachService.serve(file); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.domain; | |
import lombok.AllArgsConstructor; | |
import lombok.Data; | |
import lombok.NoArgsConstructor; | |
import org.hibernate.annotations.CreationTimestamp; | |
import javax.persistence.Entity; | |
import javax.persistence.Id; | |
import java.sql.Timestamp; | |
import java.util.UUID; | |
@Entity | |
@Data | |
@NoArgsConstructor | |
@AllArgsConstructor | |
public class Attachment { | |
@Id | |
private UUID id; | |
private String path; | |
private String origin; | |
@CreationTimestamp | |
private Timestamp created; | |
public Attachment(UUID id, String path, String origin) { | |
this.id = id; | |
this.path = path; | |
this.origin = origin; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.repository; | |
import kr.hs.dgsw.springcrmpractice.domain.Attachment; | |
import org.springframework.data.jpa.repository.JpaRepository; | |
import java.util.Optional; | |
import java.util.UUID; | |
public interface AttachRepository extends JpaRepository<Attachment, Long> { | |
Optional<Attachment> findById(UUID id); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.service; | |
import kr.hs.dgsw.springcrmpractice.domain.Attachment; | |
import org.springframework.core.io.Resource; | |
import org.springframework.http.ResponseEntity; | |
import org.springframework.web.multipart.MultipartFile; | |
public interface AttachService { | |
Attachment attach(MultipartFile file); | |
ResponseEntity<Resource> serve(String file); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.service; | |
import kr.hs.dgsw.springcrmpractice.domain.Attachment; | |
import kr.hs.dgsw.springcrmpractice.repository.AttachRepository; | |
import org.apache.tomcat.util.http.fileupload.FileUtils; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.core.io.Resource; | |
import org.springframework.core.io.UrlResource; | |
import org.springframework.http.HttpHeaders; | |
import org.springframework.http.ResponseEntity; | |
import org.springframework.stereotype.Service; | |
import org.springframework.web.multipart.MultipartFile; | |
import javax.annotation.PostConstruct; | |
import java.io.File; | |
import java.io.IOException; | |
import java.nio.file.Files; | |
import java.nio.file.Path; | |
import java.nio.file.Paths; | |
import java.util.Optional; | |
import java.util.UUID; | |
@Service | |
public class AttachServiceImpl implements AttachService { | |
private final AttachRepository attachRepository; | |
@Autowired | |
public AttachServiceImpl(AttachRepository attachRepository) { | |
this.attachRepository = attachRepository; | |
} | |
@Value("${spring.jpa.hibernate.ddl-auto}") | |
private String DDLMode; | |
@PostConstruct | |
private void init() throws IOException { | |
if (DDLMode.equals("create") || DDLMode.equals("create-drop")) { | |
deleteFiles(new File(System.getProperty("user.dir") + "\\upload\\")); | |
} | |
} | |
private boolean deleteFiles(File file) { | |
File[] flist = null; | |
if (file == null) { | |
return false; | |
} | |
if (file.isFile()) { | |
return file.delete(); | |
} | |
if (!file.isDirectory()) { | |
return false; | |
} | |
flist = file.listFiles(); | |
if (flist != null && flist.length > 0) { | |
for (File f: flist) { | |
if (!deleteFiles(f)) { | |
return false; | |
} | |
} | |
} | |
return file.delete(); | |
} | |
@Override | |
public Attachment attach(MultipartFile file) { | |
UUID uuid = UUID.randomUUID(); | |
String path = "\\upload\\" + uuid.toString(); | |
try { | |
File dest = new File(System.getProperty("user.dir") + path); | |
dest.getParentFile().mkdirs(); | |
file.transferTo(dest); | |
} | |
catch (IOException e) { | |
return null; | |
} | |
return attachRepository.save(new Attachment(uuid, path, file.getOriginalFilename())); | |
} | |
@Override | |
public ResponseEntity<Resource> serve(String id) { | |
Optional<Attachment> target = attachRepository.findById(UUID.fromString(id)); | |
if (!target.isPresent()) { | |
return ResponseEntity.notFound().build(); | |
} | |
Attachment targetFile = target.get(); | |
try { | |
Path path = Paths.get(new File(System.getProperty("user.dir") + targetFile.getPath()).getPath()); | |
Resource body = new UrlResource(path.toUri()); | |
if (body.exists() || body.isReadable()) { | |
return ResponseEntity | |
.ok() | |
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + targetFile.getOrigin() + "\"") | |
.body(body); | |
} | |
else { | |
throw new Exception(); | |
} | |
} | |
catch (Exception e) { | |
return ResponseEntity.status(500).build(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" | |
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> | |
<link href='//spoqa.github.io/spoqa-han-sans/css/SpoqaHanSans-kr.css' rel='stylesheet' type='text/css'> | |
<style> | |
* { | |
font-family: 'Spoqa Han Sans', 'Spoqa Han Sans JP', sans-serif; | |
} | |
</style> | |
<title>Spring CRM</title> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="input-group mt-5"> | |
<input type="text" class="form-control w-20" placeholder="Enter Username.." id="username"> | |
<div class="input-group-append"> | |
<button class="btn btn-outline-secondary" onclick="addUser()">확인</button> | |
</div> | |
</div> | |
<table class="table mt-5"> | |
<thead> | |
<tr> | |
<th scope="col">프사</th> | |
<th scope="col">유저 이름</th> | |
<th scope="col">이메일</th> | |
<th scope="col">수정</th> | |
<th scope="col">삭제</th> | |
</tr> | |
</thead> | |
<tbody id="insert"> | |
</tbody> | |
</table> | |
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editModalLabel" aria-hidden="true"> | |
<div class="modal-dialog" role="document"> | |
<div class="modal-content"> | |
<div class="modal-header"> | |
<h5 class="modal-title" id="editModalLabel">댓글 수정하기</h5> | |
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> | |
<span aria-hidden="true">×</span> | |
</button> | |
</div> | |
<div class="modal-body"> | |
<input type="hidden" id="edit-id"> | |
<input type="hidden" id="file-uuid"> | |
<input type="text" class="form-control mb-2" placeholder="Enter username.." id="edit-username"> | |
<input type="text" class="form-control mb-2" placeholder="Enter email.." id="edit-email"> | |
<input type="file" class="form-control mb-2" id="edit-avatar"> | |
</div> | |
<div class="modal-footer"> | |
<button type="button" class="btn btn-secondary" data-dismiss="modal">취소</button> | |
<button type="button" class="btn btn-primary" onclick="editUser()" data-dismiss="modal">수정</button> | |
<!-- event attribute에 this 넣으면 전달 가능 --> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> | |
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> | |
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> | |
<script> | |
const submit = async () => { | |
let formData = new FormData(); | |
formData.append("file", document.getElementById("file").files[0]); | |
console.log(await axios.post("/attach", formData, { | |
headers: { | |
"Content-Type": "multipart/form-data" | |
} | |
})); | |
}; | |
</script> | |
<script> | |
$('#editModal').on('hidden.bs.modal', e => { | |
document.getElementById("edit-id").value = ""; | |
document.getElementById("file-uuid").value = ""; | |
document.getElementById("edit-username").value = ""; | |
document.getElementById("edit-email").value = ""; | |
document.getElementById("edit-avatar").files[0] = null; | |
}); | |
const spawnElement = data => { | |
document.getElementById("insert").innerHTML += ` | |
<tr user-id="${data.id}"> | |
<td><img src="/attach/${data.avatarFile}" alt="프로필 사진" class="rounded" style="max-height: 80px;"></td> | |
<td>${data.username}</td> | |
<td>${data.email}</td> | |
<td><button type="button" class="btn btn-primary" data-toggle="modal" data-target="#editModal" onclick="setEditId(${data.id})">수정</button></td> | |
<td><button type="button" class="btn btn-danger" onclick="deleteUser(${data.id})">삭제</button></td> | |
</tr> | |
`; | |
}; | |
const retreiveUsers = async () => { | |
document.getElementById("insert").innerHTML = ""; | |
const { data } = await axios.get("/user"); | |
console.log(data); | |
data.forEach(el => spawnElement(el)); | |
}; | |
const addUser = async () => { | |
const value = document.getElementById("username").value.trim(); | |
if (value === null || value === "") { | |
alert("값을 입력해주세요."); | |
return; | |
} | |
const { data } = await axios.post(`/user`, { | |
username: value | |
}); | |
if (data !== null) { | |
spawnElement(data); | |
} | |
document.getElementById("username").value = ""; | |
}; | |
const deleteUser = async id => { | |
const { data } = await axios.delete(`/user/${id}`); | |
if (data !== null && data) { | |
const element = document.querySelector(`[user-id="${id}"]`); | |
document.getElementById("insert").removeChild(element); | |
} | |
}; | |
const setEditId = async id => { | |
document.getElementById("edit-id").value = id; | |
const { data } = await axios.get(`/user/${id}`); | |
document.getElementById("edit-id").value = id; | |
document.getElementById("file-uuid").value = data.avatarFile; | |
document.getElementById("edit-username").value = data.username; | |
document.getElementById("edit-email").value = data.email; | |
}; | |
const editUser = async () => { | |
const id = document.getElementById("edit-id").value; | |
const value = { | |
username: document.getElementById("edit-username").value, | |
email: document.getElementById("edit-email").value, | |
avatarFile: await uploadPictureAndSync() | |
}; | |
console.log(value); | |
if (value.username === "" || value.email === "") { | |
alert("값을 입력해주세요."); | |
return; | |
} | |
const { data } = await axios.put(`/user/${id}`, { | |
username: value.username, | |
email: value.email, | |
avatarFile: value.avatarFile | |
}); | |
if (data !== null && data) { | |
await retreiveUsers(); | |
} | |
}; | |
const uploadPictureAndSync = async () => { | |
let formData = new FormData(); | |
formData.append("file", document.getElementById("edit-avatar").files[0]); | |
const { data } = await axios.post("/attach", formData, { | |
headers: { | |
"Content-Type": "multipart/form-data" | |
} | |
}); | |
console.log(data.id); | |
return data.id; | |
}; | |
document.addEventListener("DOMContentLoaded", retreiveUsers); | |
</script> | |
</body> | |
</html> | |
<!-- | |
<input type="file" id="file"> | |
<button onclick="submit()">전송</button> | |
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> | |
<script> | |
const submit = async () => { | |
let formData = new FormData(); | |
formData.append("file", document.getElementById("file").files[0]); | |
console.log(await axios.post("/attach", formData, { | |
headers: { | |
"Content-Type": "multipart/form-data" | |
} | |
})); | |
}; | |
path: "\upload\asdsad.jpg"; | |
</script> | |
--> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.domain; | |
import lombok.AllArgsConstructor; | |
import lombok.Data; | |
import lombok.NoArgsConstructor; | |
import org.hibernate.annotations.CreationTimestamp; | |
import org.hibernate.annotations.UpdateTimestamp; | |
import javax.persistence.Entity; | |
import javax.persistence.GeneratedValue; | |
import javax.persistence.Id; | |
import java.time.LocalDateTime; | |
import java.util.UUID; | |
@Entity | |
@Data | |
@NoArgsConstructor | |
@AllArgsConstructor | |
public class User { | |
@Id | |
@GeneratedValue | |
private Long id; | |
private UUID avatarFile; | |
private String username; | |
private String email; | |
@CreationTimestamp | |
private LocalDateTime created; | |
@UpdateTimestamp | |
private LocalDateTime updated; | |
public User(String username, String email) { | |
this.username = username; | |
this.email = email; | |
} | |
public User(UUID avatarFile, String username, String email) { | |
this.avatarFile = avatarFile; | |
this.username = username; | |
this.email = email; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.controller; | |
import kr.hs.dgsw.springcrmpractice.domain.User; | |
import kr.hs.dgsw.springcrmpractice.service.UserService; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.web.bind.annotation.*; | |
import java.util.List; | |
@RestController | |
public class UserController { | |
private final UserService userService; | |
@Autowired | |
public UserController(UserService userService) { | |
this.userService = userService; | |
} | |
@GetMapping("/user") | |
public List<User> listUsers() { | |
return userService.listUsers(); | |
} | |
@GetMapping("/user/{id}") | |
public User getUser(@PathVariable Long id) { | |
return userService.getUser(id); | |
} | |
@PostMapping("/user") | |
public User addUser(@RequestBody User user) { | |
return userService.addUser(user); | |
} | |
@PutMapping("/user/{id}") | |
public User updateUser(@PathVariable Long id, @RequestBody User user) { | |
return userService.updateUser(id, user); | |
} | |
@DeleteMapping("/user/{id}") | |
public boolean deleteUser(@PathVariable Long id) { | |
return userService.deleteUser(id); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.repository; | |
import kr.hs.dgsw.springcrmpractice.domain.User; | |
import org.springframework.data.jpa.repository.JpaRepository; | |
import java.util.Optional; | |
public interface UserRepository extends JpaRepository<User, Long> { | |
Optional<User> findByEmail(String email); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.service; | |
import kr.hs.dgsw.springcrmpractice.domain.User; | |
import java.util.List; | |
public interface UserService { | |
List<User> listUsers(); | |
User getUser(Long id); | |
User addUser(User user); | |
User updateUser(Long id, User user); | |
boolean deleteUser(Long id); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package kr.hs.dgsw.springcrmpractice.service; | |
import kr.hs.dgsw.springcrmpractice.domain.User; | |
import kr.hs.dgsw.springcrmpractice.repository.UserRepository; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.stereotype.Service; | |
import javax.annotation.PostConstruct; | |
import java.util.List; | |
import java.util.Optional; | |
import java.util.UUID; | |
@Service | |
public class UserServiceImpl implements UserService { | |
private final UserRepository userRepository; | |
@Autowired | |
public UserServiceImpl(UserRepository userRepository) { | |
this.userRepository = userRepository; | |
} | |
@Value("${spring.jpa.hibernate.ddl-auto}") | |
private String DDLMode; | |
@PostConstruct | |
private void init() { | |
if (DDLMode.equals("create") || DDLMode.equals("create-drop")) { | |
// Dummy Data | |
} | |
} | |
@Override | |
public List<User> listUsers() { | |
return userRepository.findAll(); | |
} | |
@Override | |
public User getUser(Long id) { | |
return userRepository.findById(id).orElse(null); | |
} | |
@Override | |
public User addUser(User user) { | |
Optional<User> target = userRepository.findByEmail(user.getEmail()); | |
if (target.isPresent()) { | |
return null; | |
} | |
return userRepository.save(user); | |
} | |
@Override | |
public User updateUser(Long id, User user) { | |
Optional<User> target = userRepository.findById(id); | |
if (!target.isPresent()) { | |
return null; | |
} | |
User targetUser = target.get(); | |
targetUser.setUsername(user.getUsername() != null ? user.getUsername() : targetUser.getUsername()); | |
targetUser.setEmail(user.getEmail() != null ? user.getEmail() : targetUser.getEmail()); | |
targetUser.setAvatarFile(user.getAvatarFile() != null ? user.getAvatarFile() : targetUser.getAvatarFile()); | |
return userRepository.save(targetUser); | |
} | |
@Override | |
public boolean deleteUser(Long id) { | |
Optional<User> target = userRepository.findById(id); | |
if (!target.isPresent()) { | |
return false; | |
} | |
try { | |
userRepository.deleteById(id); | |
} | |
catch (Exception e) { | |
return false; | |
} | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment