Spring Boot休息控制器。返回对象,包括遗产属性和异常处理

时间:2018-08-17 12:33:53

标签: java spring spring-boot spring-data

我在Spring Boot RestController中挣扎。

UserService

@Service
public class UserService implements IUserService {

    @Autowired
    public PasswordEncoder passwordEncoder;

    private final UserRepository userRepository;

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

    public UserLoginResponse register(RegisterUserRequest request) throws NoValidRegisterDataException, Exception {
        UserLoginResponse response = new UserLoginResponse();
        UserEntity user = request.getUser();

        if(!this.checkUserDataValidity(user)) {
            throw new NoValidRegisterDataException();
        }

        user.setPassword(this.encodePassword(user.getPassword()));

        try {
            user = this.userRepository.save(user);
        } catch (Exception e) {
            throw new Exception("Database save error");
        }

        response.addMessage(new ResponseMessage(ResponseMessageType.success, "Uživatel úspěšně registrován"));
        response.setUser(user);

        //TODO token handler

        return response;
    }

    private boolean checkUserDataValidity(UserEntity user) {
        return (user.getEmail() != null && user.getPassword() != null && user.getUsername() != null);
    }

    private String encodePassword(String password) {
        return this.passwordEncoder.encode(password);
    }
}

到目前为止,我有一个服务的注册(主要方法)。由UserController调用(下面的代码)

@RestController
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping(method = POST, value = "/user/register")
    @CrossOrigin
        public UserLoginResponse register(RegisterUserRequest request,
                                          HttpServletResponse servletResponse) {
            UserLoginResponse response = new UserLoginResponse();

            try {
                response = this.userService.register(request);
            } catch (NoValidRegisterDataException e) {
response.addMessage(new ResponseMessage(ResponseMessageType.danger, e.getMessage()));
                servletResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            } catch (Exception e) {
                response.addMessage(new ResponseMessage(ResponseMessageType.danger, e.getMessage()));
                servletResponse.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
            }

            return response;
        }
}

我返回UserLoginResponse对象。我在请求中得到了RegisterUserRequest对象(基本上是带有用户数据的对象)

public class UserLoginResponse extends Response {
    private UserEntity user;

    private String userToken;

    public UserLoginResponse() {}

    public UserLoginResponse(ArrayList<ResponseMessage> messages, UserEntity user, String userToken) {
        super(messages);
        this.user = user;
        this.userToken = userToken;
    }

    public UserEntity getUser() {
        return user;
    }

    public void setUser(UserEntity user) {
        this.user = user;
    }

    public String getUserToken() {
        return userToken;
    }

    public void setUserToken(String userToken) {
        this.userToken = userToken;
    }
}

然后扩展Response对象,该对象内部具有一个属性。我要发送到前端的邮件列表

public class Response {
    private ArrayList<ResponseMessage> messages;

    public Response() {}

    public Response(ArrayList<ResponseMessage> messages) {
        this.messages = messages;
    }

    public void addMessage(ResponseMessage message) {
        if(this.messages == null) {
            this.messages = new ArrayList<>();
        }

        this.messages.add(message);
    }
}

第一个问题是,当发生错误(错误的用户数据,其他错误)时,我得到了空的UserLoginResponse对象。多数情况下还可以,但是我没有消息。 (错误消息是在UserController的catch块中设置的,因此它们应该在那里。)

第二个问题是,即使我在UserController的第一个catch块中(在一般Exception之上)抛出NoValidRegisterDataException,异常也是由最后一个catch块处理的。我怎样才能解决这个问题?我以为异常是由它适合的第一个catch块(从上到下)处理的。

编辑:我已经解决了第二个问题。我没有注意到在抛出异常的情况下抛出了nullpointerexception。因此,它现在变得有意义。我添加了空检查,异常现在可以正常工作。但是我仍然不知道如何返回整个响应,包括来自父响应对象的消息。

1 个答案:

答案 0 :(得分:0)

我认为您的代码有几个问题:

1)请避免在Spring服务和控制器中使用检查的异常。它们只会增加噪音,尤其是使用各种try-catch子句时。理想情况下,如果要抛出异常,只需抛出一个运行时异常,并准备好一个异常处理程序以捕获它并创建您适当的响应。您可以在这里查看这些内容:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html

2)避免使用catch子句来捕获Exception。在大多数情况下,如果发生一些不必要的异常,这将使您的流程混乱。只是让它冒泡到Spring的默认异常处理程序即可。

3)避免继承,而只支持组合。我认为扩展POJO并不是一件好事。

4)避免混合使用字段注入和构造函数注入。在大多数情况下,这是灾难的根源。

5)在每次手动设置servletResponse时,我看不到任何意义。只需将响应对象包装到ResponseEntity中,该对象也可以有效地携带状态码。