首页 > 解决方案 > Spring Boot 休息控制器。返回对象,包括遗产属性和异常处理

问题描述

我在弹簧靴休息控制器方面遇到了困难。

用户服务

@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 块(一般异常)中抛出 NoValidRegisterDataException,异常也是由最后一个 catch 块处理的。我怎样才能解决这个问题?我认为异常是由它适合的第一个 catch 块处理的(从上到下)。

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

标签: javaspringspring-bootspring-data

解决方案


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

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

2) 避免使用 catch 子句 catch Exception。在大多数情况下,如果发生一些不需要的异常,这会打乱您的流程。让它冒泡到 Spring 的默认异常处理程序。

3)避免继承,只支持组合作为回报。在我看来,扩展 POJO 并不是一件好事。

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

5)我看不到每次手动设置 servletResponse 的任何意义。只需将您的响应对象包装成一个ResponseEntity也可以有效携带状态代码的对象。


推荐阅读