Spring Boot 2.0 Projects
上QQ阅读APP看书,第一时间看更新

Using Services to encapsulate business logic

It is a good practice to encapsulate business logic inside Service methods so that controllers and repositories are loosely coupled. The following Service is written to encapsulate business logic for Comment:

@Service
@Transactional(readOnly = true)
public class CommentService {

private static final Logger LOGGER = LoggerFactory.getLogger(CommentService.class);

private final CommentRepository commentRepository;

public CommentService(CommentRepository commentRepository) {
this.commentRepository = commentRepository;
}

@Transactional(rollbackFor = Exception.class)
public List<Comment> saveAll(List<Comment> comments) {
LOGGER.info("Saving {}", comments);
return commentRepository.saveAll(comments);
}

public List<Comment> getAllCommentsForToday() {
LocalDate localDate = LocalDate.now();
return commentRepository.findByCreatedYearAndMonthAndDay(localDate.getYear(),
localDate.getMonth().getValue(), localDate.getDayOfMonth());
}
}

The CommentService method in the preceding code is annotated with the @Service stereotype annotation to mark it as a Spring service. Also, it has the @Transactional annotation (learn more about Spring Transaction in the reference documentation). The CommentRepository will be auto-wired using the CommentService constructor argument. Another notable thing is that the CommentService.saveAll method is annotated with the @Transactional annotation with rollbackFor set to the Exception class. This means that any code inside that method will be enclosed inside a transaction and, if an exception is thrown, JpaTransactionManager will roll back the changes it made in the database within that transaction.

Likewise, the following UserService is used for User:

@Service
@Transactional(readOnly = true)
public class UserService implements UserDetailsService {

private final UserRepository userRepository;

public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}

@Override
public UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException {
User user = userRepository.findByUsername(username);

if(user == null) {
throw new UsernameNotFoundException(username);
}

return new
org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(),
Arrays.asList(new SimpleGrantedAuthority(user.getRole())));
}

@Transactional(rollbackFor = Exception.class)
public User create(User user) {
return userRepository.save(user);
}
}

This is similar to CommentService but also implements the Spring Security UserDetailsService interface in addition to supporting User detail loading. More on this will be discussed in the Using Spring Security for authentication and authorization section of this chapter.