springboot统一restful返回值及统一异常处理

统一返回restful数据:

首先确定需要返回的json数据的格式,定义一个统一返回类

package com.unicom.microservice.peixun.peixun_matb3.Response;

import com.unicom.microservice.peixun.peixun_matb3.enums.UnicomResponseEnums;

/**
 * @program: 测试
 * @description:返回的JSON数据结构标准
 * @author: mtb
 * @create: 2018-10-17 09:01
 **/
public class ResponseBean <T>{
	private boolean success;
	private T data;
	private String errCode;
	private String errMsg;

	public ResponseBean(){}

	public ResponseBean(boolean success, T data) {
		super();
		this.success = success;
		this.data = data;
	}

	@Override
	public String toString() {
		return "ResponseBean{" +
				"success=" + success +
				", data=" + data +
				", errCode='" + errCode + '\'' +
				", errMsg='" + errMsg + '\'' +
				'}';
	}

	public ResponseBean(boolean success, T data, String errCode, String errMsg) {
		super();
		this.success = success;
		this.data = data;
		this.errCode = errCode;
		this.errMsg = errMsg;
	}

	public ResponseBean(boolean success, String errCode, String errMsg) {
		this.success = success;
		this.errCode = errCode;
		this.errMsg = errMsg;
	}
	public ResponseBean(boolean success,UnicomResponseEnums enums){
		this.success=success;
		this.errCode=enums.getCode();
		this.errMsg=enums.getMsg();
	}
	public ResponseBean(boolean success,T data,UnicomResponseEnums enums){
		this.success=success;
		this.data=data;
		this.errCode=enums.getCode();
		this.errMsg=enums.getMsg();
	}
	public boolean isSuccess() {
		return success;
	}
	public void setSuccess(boolean success) {
		this.success = success;
	}
	public T getData() {
		return data;
	}
	public void setData(T data) {
		this.data = data;
	}
	public String getErrCode() {
		return errCode;
	}
	public void setErrCode(String errCode) {
		this.errCode = errCode;
	}
	public String getErrMsg() {
		return errMsg;
	}
	public void setErrMsg(String errMsg) {
		this.errMsg = errMsg;
	}

}

新建一个枚举类,将常用提示信息及错误信息写入:

package com.unicom.microservice.peixun.peixun_matb3.enums;

/**
 * @program: 测试
 * @description:友好提示枚举
 * @author: mtb
 * @create: 2018-10-17 08:52
 **/


public enum UnicomResponseEnums {

	SYSTEM_ERROR("-001","系统异常"),
	BAD_REQUEST("-002","错误的请求参数"),
	NOT_FOUND("-003","找不到请求路径!"),
	CONNECTION_ERROR("-004","网络连接请求失败!"),
	METHOD_NOT_ALLOWED("-005","不合法的请求方式"),
	DATABASE_ERROR("-004","数据库异常"),
	BOUND_STATEMENT_NOT_FOUNT("-006","找不到方法!"),
	REPEAT_REGISTER("001","重复注册"),
	NO_USER_EXIST("002","用户不存在"),
	INVALID_PASSWORD("003","密码错误"),
	NO_PERMISSION("004","非法请求!"),
	SUCCESS_OPTION("005","操作成功!"),
	NOT_MATCH("-007","用户名和密码不匹配"),
	FAIL_GETDATA("-008","获取信息失败"),
	BAD_REQUEST_TYPE("-009","错误的请求类型"),
	INVALID_MOBILE("010","无效的手机号码"),
	INVALID_EMAIL("011","无效的邮箱"),
	INVALID_GENDER("012","无效的性别"),
	REPEAT_MOBILE("014","已存在此手机号"),
	REPEAT_EMAIL("015","已存在此邮箱地址"),
	NO_RECORD("016","没有查到相关记录"),
	LOGIN_SUCCESS("017","登陆成功"),
	LOGOUT_SUCCESS("018","已退出登录"),
	SENDEMAIL_SUCCESS("019","邮件已发送,请注意查收"),
	EDITPWD_SUCCESS("020","修改密码成功"),
	No_FileSELECT("021","未选择文件"),
	FILEUPLOAD_SUCCESS("022","上传成功"),
	NOLOGIN("023","未登陆"),
	ILLEGAL_ARGUMENT("024","参数不合法"),
	ERROR_IDCODE("025","验证码不正确");

	private String code;
	private String msg;
	private UnicomResponseEnums(String code, String msg) {

		this.code = code;
		this.msg = msg;
	}
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}



}

建立一个自定义异常继承 RuntimeException类,以便抛出自定义异常

package com.unicom.microservice.peixun.peixun_matb3.exception;

import com.unicom.microservice.peixun.peixun_matb3.enums.UnicomResponseEnums;

/**
 * @program: 测试
 * @description:自定义异常
 * @author: mtb
 * @create: 2018-10-17 08:57
 **/
public class UnicomRuntimeException extends RuntimeException {
	private static final long serialVersionUID = 1L;
	protected String code;

	protected String msg;

	protected String message;//打印出的日志信息

	public UnicomRuntimeException(UnicomResponseEnums enums, String message) {
		super();
		this.code = enums.getCode();
		this.msg = enums.getMsg();
		this.message = message;
	}

	public UnicomRuntimeException(UnicomResponseEnums enums) {
		super();
		this.code = enums.getCode();
		this.msg = enums.getMsg();
	}


	public String getCode() {
		return code;
	}


	public void setCode(String code) {
		this.code = code;
	}


	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}




	public UnicomRuntimeException() {
		super();
	}

	public UnicomRuntimeException(String message, Throwable cause) {
		super(message, cause);
	}

	public UnicomRuntimeException(String message) {
		super(message);
	}

}

新建一个异常处理类:

package com.unicom.microservice.peixun.peixun_matb3.exception;
import javax.servlet.http.HttpServletRequest;

import com.unicom.microservice.peixun.peixun_matb3.Response.ResponseBean;
import com.unicom.microservice.peixun.peixun_matb3.enums.UnicomResponseEnums;
import org.apache.ibatis.binding.BindingException;
import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.net.ConnectException;
import java.sql.SQLException;


/**
 * @program: 测试
 * @description:全局的异常处理类
 * @author: mtb
 * @create: 2018-10-19 11:38
 **/
@RestControllerAdvice(annotations={RestController.class,Controller.class})
public class SpringExceptionHandle {


	private static final Logger logger = LoggerFactory.getLogger(SpringExceptionHandle.class);
	/**
	 * 请求参数类型错误异常的捕获
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value={BindException.class})
	@ResponseBody
	@ResponseStatus(value=HttpStatus.BAD_REQUEST)
	public ResponseBean<String> badRequest(BindException e){
		logger.error("occurs error when execute method ,message {}",e.getMessage());
		return new ResponseBean<>(false, UnicomResponseEnums.BAD_REQUEST);
	}

	/**
	 * 404错误异常的捕获
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value={NoHandlerFoundException.class})
	@ResponseBody
	@ResponseStatus(value=HttpStatus.NOT_FOUND)
	public ResponseBean<String> badRequestNotFound(BindException e){
		logger.error("occurs error when execute method ,message {}",e.getMessage());
		return new ResponseBean<>(false,null, UnicomResponseEnums.NOT_FOUND);
	}

	/**
	 * mybatis未绑定异常
	 * @param e
	 * @return
	 */
	@ExceptionHandler(BindingException.class)
	@ResponseBody
	@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
	public ResponseBean<String> mybatis(Exception e){
		logger.error("occurs error when execute method ,message {}",e.getMessage());
		return new ResponseBean<>(false,UnicomResponseEnums.BOUND_STATEMENT_NOT_FOUNT);
	}
	/**
	 * 自定义异常的捕获
	 * 自定义抛出异常。统一的在这里捕获返回JSON格式的友好提示。
	 * @param exception
	 * @param request
	 * @return
	 */
	@ExceptionHandler(value={UnicomRuntimeException.class})
	@ResponseBody
	@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
	public <T> ResponseBean<T> sendError(UnicomRuntimeException exception,HttpServletRequest request){
		String requestURI = request.getRequestURI();
		logger.error("occurs error when execute url ={} ,message {}",requestURI,exception.getMsg());
		return new ResponseBean<>(false,exception.getCode(),exception.getMsg());
	}
	/**
	 * 数据库操作出现异常
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value={SQLException.class,DataAccessException.class})
	@ResponseBody
	@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
	public ResponseBean<String> systemError(Exception e){
		logger.error("occurs error when execute method ,message {}",e.getMessage());
		return new ResponseBean<>(false, UnicomResponseEnums.DATABASE_ERROR);
	}
	/**
	 * 网络连接失败!
	 * @param e
	 * @return
	 */
	@ExceptionHandler(value={ConnectException.class})
	@ResponseBody
	@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
	public ResponseBean<String> connect(Exception e){
		logger.error("occurs error when execute method ,message {}",e.getMessage());
		return new ResponseBean<>(false, UnicomResponseEnums.CONNECTION_ERROR);
	}

	@ExceptionHandler(value={Exception.class})
	@ResponseBody
	@ResponseStatus(value=HttpStatus.METHOD_NOT_ALLOWED)
	public ResponseBean<String> notAllowed(Exception e){
		logger.error("occurs error when execute method ,message {}",e.getMessage());
		return new ResponseBean<>(false, UnicomResponseEnums.METHOD_NOT_ALLOWED);
	}


}

建立一个测试controller类:

package com.unicom.microservice.peixun.peixun_matb3.web;/**
 * Created by matengbing on 2018/10/15.
 */

import com.unicom.microservice.peixun.peixun_matb3.Response.ResponseBean;
import com.unicom.microservice.peixun.peixun_matb3.enums.UnicomResponseEnums;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;

/**
 * @program: 测试
 * @description:测试接口
 * @author: mtb
 * @create: 2018-10-15 11:26
 **/

@RestController
@ApiIgnore
//@RequestMapping(value = "sayHello")
public class HelloController {

	@CrossOrigin
	@ApiOperation(value = "hello")
	@RequestMapping(value = "/hello",method = RequestMethod.GET)
	public ResponseBean<UnicomResponseEnums> sayHello(){
		ResponseBean responseBean=new ResponseBean(true,UnicomResponseEnums.SUCCESS_OPTION);
		return responseBean;
	}
}

使用postman测试接口:

注意要配置springboot启动类,扫描controller等注解类被扫描到

@API等注解是swagger的注解,如果没有使用到可以删除

我们在实现数据库操作的方法中try,catch,捕捉到异常后,抛出一个自定义异常

@Transactional
	@Override
	public int addUser(User user) {
		try {
			user.setUserpwd(DigestUtils.md5DigestAsHex(user.getUserpwd().getBytes()));
			userMapper.insertUser(user);
			return user.getId();
		}catch (Exception e){
			throw new UnicomRuntimeException(UnicomResponseEnums.FAIL_INSERTUSER);
		}
	}

接着拦截404错误

参考文章

package com.unicom.peixun.web;

import com.unicom.peixun.Response.ResponseBean;
import com.unicom.peixun.enums.UnicomResponseEnums;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * @program: peixun_matb3
 * @description:
 * @author: matengbing
 * @create: 2018-10-20 09:08
 **/
@RestController
public class MyBasicErrorController implements ErrorController {

	private static final String ERROR_PATH="/error";
	@RequestMapping("/error")
	public ResponseBean<Object> handleError(HttpServletRequest request){
		//获取statusCode:401,404,500
		Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
		if(statusCode==404){
			return new ResponseBean<>(false,null,UnicomResponseEnums.NOT_FOUND);
		}else {
			return new ResponseBean<>(false,null,UnicomResponseEnums.METHOD_NOT_ALLOWED);
		}

	}
	@Override
	public String getErrorPath() {
		return ERROR_PATH;
	}

}

用于登录拦截的拦截器实现返回restful数据:

package com.unicom.peixun.inteceptor;

import com.alibaba.fastjson.JSON;
import com.unicom.peixun.Response.ResponseBean;
import com.unicom.peixun.domain.User;
import com.unicom.peixun.enums.UnicomResponseEnums;
import com.unicom.peixun.web.UserController;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.PrintWriter;

/**
 * @program: peixun_matb3
 * @description:
 * @author: matengbing
 * @create: 2018-10-18 10:40
 **/
@Component
public class LoginInterceptor implements HandlerInterceptor {

	private static Logger logger=Logger.getLogger(LoginInterceptor.class);

	@Autowired
	UserController userController;
	//    在请求处理之前调用,只有返回true才会执行请求
	@Override
	public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
		HttpSession session=httpServletRequest.getSession();
		User user=(User) session.getAttribute("user");
		//登录过得用户直接通过
		if(user!=null){
			return true;
		}

		//未登录用户拦截,返回json数据
		httpServletResponse.setCharacterEncoding("UTF-8");
		httpServletResponse.setContentType("application/json; charset=utf-8");
		PrintWriter out = httpServletResponse.getWriter() ;
		try{

			ResponseBean<Object> responseBean=new ResponseBean<>(false,null,UnicomResponseEnums.NOLOGIN);
			out = httpServletResponse.getWriter();
			out.append(JSON.toJSON(responseBean).toString());
			return false;
		}
		catch (Exception e) {
			e.printStackTrace();
			httpServletResponse.sendError(500);
			return false;
		}

	}

	@Override
	public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

	}

	@Override
	public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

	}
}

拦截器需要配置@configuration

package com.unicom.peixun.configuration;

import com.unicom.peixun.inteceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * @program: 
 * @description:
 * @author: mtb
 * @create: 2018-10-18 10:50
 **/
@Configuration
public class LoginAdapter extends WebMvcConfigurerAdapter {
	@Autowired
	LoginInterceptor loginInterceptor;

	@Override
	public void addInterceptors(InterceptorRegistry registry) {

		registry.addInterceptor(loginInterceptor)
				.addPathPatterns("/**")
				.excludePathPatterns("/login")
				.excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");

		super.addInterceptors(registry);
	}

	/**
	 * 配置静态访问资源
	 * @param registry
	 */
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {

		registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
		registry.addResourceHandler("swagger-ui.html")
				.addResourceLocations("classpath:/META-INF/resources/");
		registry.addResourceHandler("/webjars/**")
				.addResourceLocations("classpath:/META-INF/resources/webjars/");

		super.addResourceHandlers(registry);

	}

}

配置了拦截器拦截所有请求,不拦截/login,swagger的相关请求,静态资源的请求,

如果拦截了/login会出现循环重定向报错

如果拦截了swagger的相关请求,查看swagger文档时看不到相应资源

猜你喜欢

转载自blog.csdn.net/matengbing/article/details/83188833