https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html 를 참고하여 정리했습니다.
📝 시작하기전
나 같은 경우 도메인형 디렉터리 구조를 사용한다.
✏️ 전체 구조 (package 구조)
(1) JPA package 구조
(2) MyBatis package 구조
Client <-> Controller <-> Service <-> Mapper <-> DB
책에서 나온 디렉터리 구조
@Autowired Service
를 통해 service의 method를 이용한다. (사용자의 입력을 받고 서비스로 전달하는 역할)
✔️ @Controller vs @RestController
@Controller
@Controller
@RequestMapping("/")
public class HomeController {
@GetMapping
public String home(HttpSession session) {
if (!SessionUtil.getUser(session).isPresent()) {
return "login";
}
return "index";
}
}
@ResponseBody
를 사용하여 객체를 반환한다.
@RestController
@RestController
@RequestMapping("/api/users")
public class ApiUserController {
@Autowired
private UserService userService;
@PostMapping("/login")
public ResponseEntity login(@RequestBody @Valid LoginDto loginDto, HttpSession session) {
SessionUtil.setUser(session, userService.login(loginDto));
return new ResponseEntity(HttpStatus.OK);
}
}
@RequestMapping
메서드가 기본적으로 @ResponseBody
의미를 가정한다.ResponseEntity
이다.@RestController = @Controller + @ResponseBody
✔️ service
@Autowired Repository
를 통해 repository의 method를 이용한다. (Hibernate JPA를 사용하는 경우)Service Interface
를 만들기Service Interface
구현한 Class 만들기🧐 service하나만 사용하면 되지 왜 service, serviceImlp을 사용해야하는걸까?
참고하기 좋은 블로그 을 읽으면 설명이 잘되어 있다!
- 대부분 프로젝트는 인터페이스와 구현체가 1:1로 만들어져 사용되고 있기에 service 하나만 구현해도 된다.
- service를 interface로 만드는 목적은 하나의 역할을 여러 방식으로 구현하는데 있다.
✔️ Spring 환경에서 controller, service 예시
참고하기 좋은 블로그 (https://linked2ev.github.io/spring/2019/08/14/Spring-2-%EC%8A%A4%ED%94%84%EB%A7%81-MVC-%ED%8C%A8%ED%84%B4/)
@Controller
public class UserController {
@Autowired
private UserSerivce userService;
@RequestMapping(value="/getUsers")
public String getUsers(Model model) {
model.addAttribute("users",userService.getUsers());
return "user";
}
}
public interface UserSerivce {
public ArrayList getUsers();
}
@Service
public class UserServiceImpl implements UserSerivce{
@Override
public ArrayList getUsers() {
// TODO Auto-generated method stub
ArrayList arrayListOfUser = new ArrayList<>();
for(int indexOfUser = 0; indexOfUser < 100; indexOfUser++) {
User user = new User();
user.setUserId(indexOfUser);
user.setUserName("UserName"+indexOfUser);
arrayListOfUser.add(user);
}
return arrayListOfUser;
}
}
UserServiceImpl은 UserService라는 인터페이스의 구현체이므로, @Autowired
를 Controller에서 이용시 UserService라는 인터페이스를 상속한 Class 자동으로 등록시켜준다.
✔️ SpringBoot 환경에서 service
controller
@RestController
public class Controller{
@Autowried
UserService service;
@PostMapping(value = "/login")
public String login(@RequestBody HashMap<String, String> map) throws Exception {
UserDto userDto = service.login(map);
if (userDto != null) {
String token = createToken(userDto);
return token;
} else {
return "0";
}
}
}
service
@Service
public class Service{
@Autowired
UserMapper mapper;
public UserDto login(HashMap<String, String> map){return mapper.login(map);}
}
✔️ JPA 구조를 사용한 경우 service
위와 같이 Controller에서는 Service를 호출한다. 📖 A. Controller(web)
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Resource(name = "bCryptPasswordEncoder")
private PasswordEncoder bCryptPasswordEncoder;
@Autowired
private MessageSourceAccessor msa;
public User save(UserDto userDto) {
if (isExistUser(userDto.getEmail())) {
throw new UserDuplicatedException(msa.getMessage("email.duplicate.message"));
}
return userRepository.save(userDto.toEntityWithPasswordEncode(bCryptPasswordEncoder);
}
}
@Autowired Repository
를 통해 repository의 method를 이용한다.DAO로(repository)
DB에 접근하고 DTO로 데이터를 전달 받은 다음, 비즈니스 로직을 처리해 적절한 데이터를 반환한다.
✔️ SpringBoot MyBatis에서는 DAO대신 Mapper을 사용한다.
mapper
@Mapper
public interface Mapper{
UserDto login(HashMap<String, String> map);
}
<mapper namespace="com.ssaffy.happyapi.User.UserMapper">
<resultMap type="com.ssaffy.happyapi.User.UserDto" id="userDto">
<result column="id" property="id" />
<result column="pw" property="pw" />
<result column="name" property="name" />
</resultMap>
<select id="login" parameterType="map" resultMap="userDto">
select id, pw, name from user where id = #{id} and pw = #{pw}
</select>
</mapper>
✔️ JPA에서는 DAO로 repository를 사용한다.
public interface UserRepository extends JpaRepository<User, Long> {
}
extends JpaRespoitory<User, Long>
getter/setter
메서드만을 갖는다.setter
가 없다. (대신, 생성자에서 값을 할당한다.)
실제 DB의 테이블과 매칭될 클래스
@Entity
, @Column
, @Id
등을 이용한다.Entity 클래스와 DTO 클래스를 분리하는 이유
@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@ToString
public class User implements Serializable {
private static final long serialVersionUID = 7342736640368461848L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonProperty
private Long id;
@Column(nullable = false)
@JsonProperty
private String email;
@Column(nullable = false)
@JsonIgnore
private String password;
// @Override
// public boolean equals(Object o) { ... }
// @Override
// public int hashCode() { ... }
// @Override
// public String toString() { ... }
}
🔔 이외로
common
디렉터리에는 유틸러티/전역변수 관련 클래스를 넣는게 보통이다. (아직까지는 모르겠음)config
디렉터리에는@Configuration
에너테이션이 붙는 클래스를 주로 넣는다. 수동으로 스프링 컨테이너에 빈을 등록하는 방법 (swagger와 같은 것?)web
디렉터리에는@Controller
,@RestController
에너테이션이 붙는 컨트롤러 클래스가 들어간다.