一、定义异常类型
使用以下代码定义了ServiceException,集成了RuntimException,用于在系统中捕捉和返回异常信息。
@Data
@Slf4j
public class ServiceException extends RuntimeException{
private static final long serialVersionUID = 12345678123456L;
private Integer code;
private String message;
public ServiceException(Integer code) {
this.code = code;
}
public ServiceException(String message) {
this.code = 400;
this.message = message;
log.info("message:{}",this.message);
}
}
二、用户登录逻辑
1、编写Controller层
用户登录后,将密码进行加密,并将密文与数据库中的密文对比,如果一致则登录成功;否则将报错。
@PostMapping("/tokens")
public Response login(@RequestParam(value = "uid")String username,
@RequestParam(value = "pwd")String password,
HttpServletResponse response){
// 验证用户名和密码不能为空
Assert.notNull(username,"用户名不能为空");
Assert.notNull(password,"密码不能为空");
UserEntity user = userServiceImp.getUserByAccount(username);
if (user == null){
throw new ServiceException("用户名或密码错误");
}
// 将用户输入的密码进行加密
String encodePwd = SecurityUtils.md5(password, user.getUserActivationKey());
// 将密文与数据库中存储的密文进行对比,不一致则说明认证错误
if (!encodePwd.equals(user.getPassword())){
throw new ServiceException("用户名或密码错误");
}
// 操作response的header信息
String token = "123";
response.setHeader(SecurityUtils.REQUEST_AUTH_HEADER,token);
response.setHeader("Access-Controller-Expose-Header",SecurityUtils.REQUEST_AUTH_HEADER);
// 注意不要返回用户的密码和密钥
user.setPassword(null);
user.setUserActivationKey(null);
// 把user和token返回
return ResponseFactory.getSuccess("user",user,"token",token);
}
ResponseFactory的定义参考:测试平台开发(一)鉴权模块2 统一返回工厂-CSDN博客
2、编写Service层
使用用户名和密码去数据库查询
public UserEntity getUserByAccount(String username){
UserEntity userEntity = this.getOne(new QueryWrapper<UserEntity>().eq("username", username));
return userEntity;
}
3、代码中的缺陷
以上用户登录鉴权的逻辑基本完成,但存在一个问题,即如果用户验证失败,那么用户看到的返回是500错误,我们主动抛出的异常ServiceException("用户名或密码错误")只会在后台打印,用户无法看到错误信息。因此我们要使用拦截器,把错误信息返回给用户。
三、拦截异常并返回
1、定义拦截器
我们定义ResponseResultHandler并实现ResponseBodyAdvice,可以对Response进行拦截。
①supports:定义对哪种类型的方法进行拦截,此处指定了非void类型
②beforeBodyWrite:全局重写response的返回值,此处直接返回response的body就可以了
③ExceptionHandler注解:全局拦截异常,捕获到ServiceException异常后,直接使用ResponseFactory构造返回结果
@RestControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
// 指定对哪种返回类型进行拦截,此处只拦截非Void类型的方法,因为Void方法不涉及改写异常的返回
boolean isVoid = !returnType.getMethod().getReturnType().isAssignableFrom(Void.TYPE);
return isVoid;
}
// 全局重写返回值
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 改写返回值,此处返回body即为不改写,因为非异常情况下直接返回就可以。
// 举例:如果改写成return 123456,那么返回结果也会是123456
return body;
}
// 全局拦截异常,捕获到ServiceException异常后,直接使用ResponseFactory构造返回结果
@ExceptionHandler(ServiceException.class)
public Response handleServiceException(ServiceException e, HttpServletRequest request){
return ResponseFactory.getError(e.getMessage());
}
}
再次测试登录接口,可以看到已经变为修改后的返回值
标签:返回,ServiceException,String,public,user,模块,response,拦截,鉴权 From: https://blog.csdn.net/weixin_39477393/article/details/143602624