springboot-表單驗證|AOP|統一異常處理
阿新 • • 發佈:2018-12-14
@PostMapping(value = "/girls")
public Object addGirl(Girl girl) {//此處不用使用多個@RequestParam("name")
Result result = new Result("addGirl_Error", 0, false);
try {
result.setResult(commandService.addGirl(girl));
result.setType("addGirl_ACK");
return result;
} catch (Exception e) {
logger.error("新增女生失敗", e);
result.setCode(-3);
return result;
}
}
@Valid表單驗證
驗證傳進controller的物件屬性是否有錯 1.Girl實體類成員變數需要添加註解
@Min(value = 18 , message = "未滿18歲不可訪問")
private Integer age;
2.controller引數需要處理
@PostMapping( value = "/girls")
//!!!!需要加@Valid註解
public Object addGirl(@Valid Girl girl,BindingResult br) {
Result result = new Result("addGirl_Error", 0, false);
//需要處理沒驗證通過的結果,錯誤資訊返回
if (br.hasErrors()){
result.setMessage(br.getFieldError().getDefaultMessage());
return result;
}
try {
result.setResult(commandService.addGirl(girl));
result.setType("addGirl_ACK");
return result;
} catch (Exception e) {
logger.error("新增女生失敗", e);
result.setCode(-3);
return result;
}
}
使用AOP處理請求或記錄日誌
- AOP面向切面 _程式設計正規化(程式設計思想)
- 分離通用邏輯 1.引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.具體切面程式碼
/**
* 日誌寫入管理
* zjy
*/
@Aspect
@Component
public class ControllerAspect {
private final static Logger logger = LoggerFactory.getLogger(ControllerAspect.class);
@Autowired
@Qualifier("logServiceImpl")
private LogService logService;
@Autowired
private UserService userService;
@Pointcut("execution(* com.honghe.managerTool.controller.CommandController.*(..)) "
+ "|| execution(* com.honghe.managerTool.controller.UserController.*(..)) ")
public void aspect() {//攔截所有類下所有方法
}
//配置前置通知,使用在方法aspect()上註冊的切入點
@Before("aspect()")
public void before(JoinPoint joinPoint) {
String[] paramNames = ((CodeSignature) joinPoint
.getSignature()).getParameterNames();
Object[] paramValues = joinPoint.getArgs();
String userIp = "127.0.0.1";
String oprationName = joinPoint.getSignature().getName();
switch (oprationName){
case "start":
oprationName=Operation.START.value;
break;
case "stop":
oprationName=Operation.STOP.value;
break;
case "restart":
oprationName=Operation.RESTART.value;
break;
default:
return;
}
if(paramValues.length>0){
if(paramValues[0] instanceof HttpServletRequest){
HttpServletRequest request = (HttpServletRequest)paramValues[0];
userIp = ParamUtil.getIpAddress(request);
}
}
Log log = new Log(oprationName,new Date(),userIp,1);
logService.saveLog(log);
}
//配置後置通知,使用在方法aspect()上註冊的切入點
@After("aspect()")
public void after(JoinPoint joinPoint){
logger.info("after out successfully");
}
}
對http請求解析
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* @author: zhaojianyu
* @create: 2018-10-11 09:11
**/
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
/**
* 攔截所有類下所有方法
*/
@Pointcut("execution(* com.zjy.blog.blog_start.controller.HelloContraller.*(..)) ")
public void aspect() {
}
/**
* 配置前置通知,使用在方法aspect()上註冊的切入點
*/
@Before("aspect()")
public void before(JoinPoint joinPoint) {
logger.info("方法開始執行"+new Date());
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//url
logger.info("url={}",request.getRequestURL());
logger.info("uri={}",request.getRequestURI());
//請求方法
logger.info("method={}",request.getMethod());
//請求ip地址
logger.info("ip={}",request.getRemoteAddr());
//類名 類方法
logger.info("class_method={}",joinPoint.getSignature().getDeclaringTypeName()+"="+joinPoint.getSignature().getName());
//引數
logger.info("args={}",joinPoint.getArgs());
}
@After("aspect()")
public void after() {
logger.info("方法執行完畢1"+new Date());
}
@AfterReturning(returning = "object",pointcut = "aspect()")
public void afterReturning(Object object) {
logger.info("方法執行完畢2"+new Date() + object);
}
}
統一異常處理
Error和Exception區分:
Error是編譯時錯誤和系統錯誤,系統錯誤在除特殊情況下,都不需要你來關心,基本不會出現。而編譯時錯誤,如果你使用了編譯器,那麼編譯器會提示。
Exception則是可以被丟擲的基本型別,我們需要主要關心的也是這個類。
Exception又分為RunTimeException和其他Exception。
RunTimeException和其他Exception區分:
其他Exception,受檢查異常。可以理解為錯誤,必須要開發者解決以後才能編譯通過,解決的方法有兩種,1:throw到上層,2,try-catch處理。 RunTimeException:執行時異常,又稱不受檢查異常,不受檢查!不受檢查!!不受檢查!!!重要的事情說三遍,因為不受檢查,所以在程式碼中可能會有RunTimeException時Java編譯檢查時不會告訴你有這個異常,但是在實際執行程式碼時則會暴露出來,比如經典的1/0,空指標等。如果不處理也會被Java自己處理。
統一異常處理類
import com.honghe.managerTool.config.exception.MySecurityException;
import com.honghe.managerTool.entity.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 全域性處理異常
* @author zhaojianyu
* 2018 10 11
*/
/**
* @ControllerAdvice //處理所有
* @ControllerAdvice(annotations=RestController.class) //處理這個類下的異常
* @ControllerAdvice(basePackages={"com.honghe.managerTool.controller"}) //處理包下的異常
*/
@ControllerAdvice
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* @ExceptionHandler(value={RuntimeException.class,MyRuntimeException.class}) //處理需要處理的異常類
* @ExceptionHandler //處理所有異常
* @ExceptionHandler(MySecurityException.class) //處理專門的異常
*/
@ResponseBody
@ExceptionHandler
public Result exceptionHandler(Exception e) {
if (e instanceof MySecurityException){
MySecurityException me = (MySecurityException)e;
//logger.error("許可權異常",e);
return new Result(me.getCode(),false,e.getMessage());
}else if (e instanceof NullPointerException){
logger.error("空指標異常",e);
return new Result(-3,false,"空指標異常");
}else{
return new Result(-3,false,"異常");
}
}
}
自定義異常類
/**
* 許可權驗證異常
* @author zhaojianyu
*/
public class MySecurityException extends RuntimeException {
private Integer code;
/**
* 無參構造方法
*/
public MySecurityException(){
super();
}
/**
* 有參的構造方法
*/
public MySecurityException(String message,Integer code){
super(message);
this.code = code;
}
/**
* 用指定的詳細資訊和原因構造一個新的異常
*/
public MySecurityException(String message, Throwable cause){
super(message,cause);
}
/**
* 用指定原因構造一個新的異常
*/
public MySecurityException(Throwable cause) {
super(cause);
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
丟擲自定義異常
throw new MySecurityException("請求超時,請同步伺服器時間",-2);
返回值程式碼列舉類
/**
*
* 返回值列舉類
* @author: zhaojianyu
* @create: 2018-10-11 17:50
**/
public enum ResultEnum {
/**
* 異常資訊
*/
UNKONW_ERROR(-1,"未知錯誤"),
SUCCESS(0,"請求成功"),
SECURITY_EXCEPTION(-2,"許可權異常"),
PARAMS_EXCEPTION(-3,"許可權異常")
;
private Integer code;
private String message;
ResultEnum() {
}
ResultEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}