本系列文章主要为带领SpringBoot初学者入门,本人也是一名初学者,文章若有不足之处,还望大家提出批评,加以指正!
注意:本系列文章为项目入门篇,非SpringBoot基础入门篇,如无SpringBoot相关基础的童鞋推荐慕课网廖师兄的入门教程
[2小时学会Spring Boot]
[Spring Boot进阶之Web进阶]
本人的开发环境及软件版本(仅供参考)
操作系统 : macOS 10.13.2
JDK : 1.8
Tomcat : 8.5.27
IntelliJ IDEA : 2017.3.2 (Ultimate Edition)
MySQL : 5.7.21
Reids : 4.0.7
我们先来看一段Exception类的说明
* The class {@code Exception} and its subclasses are a form of
* {@code Throwable} that indicates conditions that a reasonable
* application might want to catch.
*
* The class {@code Exception} and any subclasses that are not also
* subclasses of {@link RuntimeException} are checked
* exceptions. Checked exceptions need to be declared in a
* method or constructor's {@code throws} clause if they can be thrown
* by the execution of the method or constructor and propagate outside
* the method or constructor boundary.
这段话大概的意思就是说明Exception类和RunTimeException类都是用来捕获异常的,异常的抛出则由Throwable类来负责。那么,RunTimeException和Exception又有何区别呢?我们来看一下RunTimeException类的说明
* {@code RuntimeException} is the superclass of those
* exceptions that can be thrown during the normal operation of the
* Java Virtual Machine.
*
* {@code RuntimeException} and its subclasses are unchecked
* exceptions. Unchecked exceptions do not need to be
* declared in a method or constructor's {@code throws} clause if they
* can be thrown by the execution of the method or constructor and
* propagate outside the method or constructor boundary.
原来,RunTimeException是Exception的子类,RunTimeException是在Java虚拟机运行期间可以抛出的异常,那么到这里我们就知道了,既然我们需要借用Exception来处理自定义的错误消息,那么我们肯定是要继承于RunTimeException来进行加工。接下来我们就来自定义自己的Exception吧!
我们先创建一个exception包,在该包下面新建个NoteException类
@Data
public class NoteException extends RuntimeException {
private Integer code;
public NoteException(ResultEnum resultEnum) {
super(resultEnum.getMessage());
this.code = resultEnum.getCode();
}
}
从代码中可以看到,我们定义的NoteException是继承于RuntimeException类的。这里我们需要构建好构造方法,将错误信息返回给父类,参考这一句代码
super(resultEnum.getMessage());
到这里有人可能就不太理解了,这个ResultEnum是个什么东西?有基础的小伙伴们在这里应该一眼也就能看出来这是个枚举类,里面至少有code和message这两个变量,大致猜测一下应该也能知晓这个枚举类就是用来存放错误码和错误信息的,这个类下面也会贴出来。
现在我们就来创建一个ResultEnum枚举类吧
public enum ResultEnum {
UNKNOWN_ERROR(-1, "未知错误"),
LOGIN_ERROR(1, "登录失败,用户名或密码错误"),
REQUEST_ARGS_ERROR(2, "传入参数为空"),
PASSWORD_CHECK_ERROR(3, "旧密码不正确"),
TOKEN_CHECK_ERROR(4, "用户token校验失败"),
REGISTER_ERROR_HAD(5, "用户名已存在"),
USER_ID_NON_ERROR(6, "用户ID参数必传"),
USERNAME_NON_ERROR(7, "用户名参数必传"),
PASSWORD_NON_ERROR(8, "用户密码参数必传"),
PASSWORD_NEW_NON_ERROR(9, "用户新密码参数必传"),
TOKEN_NON_ERROR(10, "token参数必传"),
PROFILE_NON_ERROR(11, "个人简介参数必传"),
NOTE_TITLE_NON_ERROR(12, "标题参数必传"),
NOTE_CONTENT_NON_ERROR(13, "内容参数必传"),
NOTE_ID_NON_ERROR(14, "noteId参数必传"),
USER_NOT_EXIST(15, "该用户不存在"),;
private Integer code;
private String message;
ResultEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
这是本项目中所用到的错误码及错误提示,但并不是很完善,有耐心的小伙伴们可以在此基础上更加完善项目哦。
到目前为止,咱们自定义的Exception与ResultEnum都已经创建完毕了,那么这样是不是系统就可以直接进行捕获了呢?当然不是!我们现在要告诉系统我们自定义的Exception在哪里,叫什么。这里我们新建个handler的包,包下新建ExceptionHandle类
@ControllerAdvice
public class ExceptionHandle {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResultVO handle(Exception e) {
//如果该异常来自于NoteException,则通过用户传入的code和message抛出
if (e instanceof NoteException) {
NoteException noteException = (NoteException) e;
return ResultVOUtil.error(noteException.getCode(), noteException.getMessage());
}
//否则直接抛出指定异常(未知错误)
else {
return ResultVOUtil.error(ResultEnum.UNKNOWN_ERROR.getCode(), ResultEnum.UNKNOWN_ERROR.getMessage());
}
}
}
这里解释一下代码中的几个注解
@ControllerAdvice 是一个@Component,@ExceptionHandler,@InitBinder和@ModelAttribute等方法需要在其基础上实现,通过这个注解Spring才能识别到这个类
@ExceptionHandler 该注解就是用来告诉Spring这个方法就是用来抛出异常
@ResponseBody 作用是以JSON形式返回结果
从上文的handle方法中可以看到该方法返回的类型为ResultVO,而ResultVO又是由ResultVOUtil类生成的,那在这里我将两个类的代码给贴一下
ResultVO
@Data
public class ResultVO<T> {
/**
* 错误码.
*/
private Integer code;
/**
* 提示信息.
*/
private String msg;
/**
* 具体内容.
*/
private T data;
}
ResultVOUtil
public class ResultVOUtil {
// 成功返回 携带内容
public static ResultVO success(Object object) {
ResultVO resultVO = new ResultVO();
resultVO.setData(object);
resultVO.setCode(0);
resultVO.setMsg("成功");
return resultVO;
}
//成功返回 不携带内容
public static ResultVO success() {
return success(null);
}
//错误返回 携带code和msg
public static ResultVO error(Integer code, String msg) {
ResultVO resultVO = new ResultVO();
resultVO.setCode(code);
resultVO.setMsg(msg);
return resultVO;
}
}
相信小伙们读一下代码就能知道这两个类有什么作用了。到这里我们把统一异常处理的所有前置条件都已经解决了,那么我们在代码中如何使用呢?下面我们来看一下在代码中的使用。
这里我就从项目中举个简单的例子,大家一看便知。
NoteService.class
public interface NoteService {
void delNote(HttpServletRequest request, UserNoteDTO userNoteDTO) throws Exception;
}
NoteServiceImpl.class
@Service
public class NoteServiceImpl implements NoteService {
@Autowired
private NoteRepository noteRepository;
@Override
public void delNote(HttpServletRequest request, UserNoteDTO userNoteDTO) throws Exception {
//判断用户是否存在
checkUser(getUserId(request));
//noteId必传
if (StringUtils.isEmpty(userNoteDTO.getNoteId()) || userNoteDTO.getNoteId() == 0) {
throw new NoteException(ResultEnum.NOTE_ID_NON_ERROR);
}
//判断用户token
checkToken(getToken(request), getUserId(request));
noteRepository.delete(userNoteDTO.getNoteId());
}
从以上两段代码中我们就可以清晰的看到,首先从Service接口中方法的定义再到类中方法的实现,都要进行throw Exception,其次从delNote方法中的代码可以看到这一句
throw new NoteException(ResultEnum.NOTE_ID_NON_ERROR);
如果从Controller层传入的参数中不包含noteId这个参数,那么将会抛出异常提示noteid为空。
本篇文章到这里也就结束了,下一篇文章我将带大家来完成Controller层的代码。
本项目的完整项目代码的github地址
https://github.com/BigWolfDean/springboot-simple-project
如果本项目对大家有一些帮助的话,麻烦给个star,fork一下,谢谢!
SpringBoot入门项目-基于JPA的App日记后台系统之项目的搭建与配置(一)
SpringBoot入门项目-SpringBoot入门项目-基于JPA的App日记后台系统之数据库的创建与JPA的CRUD(二)
SpringBoot入门项目-基于JPA的App日记后台系统之利用Exception处理自定义错误信息(三)
SpringBoot入门项目-SpringBoot入门项目-基于JPA的App日记后台系统之Controller层的编写(四)
SpringBoot入门项目-基于JPA的App日记后台系统之利用Redis与Cookie处理用户权限校验(五)