Skip to content

Instantly share code, notes, and snippets.

@hw0k
Created April 4, 2019 04:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hw0k/58deb27b996aa870728529364bcb6323 to your computer and use it in GitHub Desktop.
Save hw0k/58deb27b996aa870728529364bcb6323 to your computer and use it in GitHub Desktop.
Spring Boot를 이용한 회원관리 연습
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);
}
}
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;
}
}
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);
}
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);
}
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();
}
}
}
<!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">&times;</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>
-->
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;
}
}
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);
}
}
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);
}
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);
}
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