Web进阶
一、使用@Vaild表单验证
1.在Girl.java实体中写入的年龄age天界注解@Min(value = 18,message=”未成年”)设计最小年龄验证
@Min(value = 18,message = “未成年”)
private Integer age;
然后在GirlController.java中写入:
@PostMapping(value = “/girls”)
public Girl girlAdd(@Valid Girl girl, BindingResult bindingResult){
//bindingResult用来存放验证结果
if (bindingResult.hasErrors()){ System.out.println(bindingResult.getFieldError().getDefaultMessage());
return null;
}
二、使用AOP统一处理请求日志
1. 什么是AOP?
AOP(面向切面) OOP(面向对象) POP(面向过程)
同一件事(下雨了额,打开伞),不同实现
面向过程:假如下雨了,我打开了伞
面向对象:天气(对象)->下雨(方法) 我(对象)->打伞(方法)
从面向过程到面向对象,就是换个角度看世界,换个姿势处理问题
AOP是一种编程范式,与语言无关,是一种程序设计思想,将通用逻辑藏业务逻辑中分离出来
从上往下看:
从左往右看:
2. 使用AOP
(1)pom文件中注入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
(2)往常做法是在启动类GirlApplication的类名上加@SpringBootApplication注解,但是AOP不需要加
(3)在main的java下建立处理文件aspect包,再在报下建立HttpAspect类,对Controller中的方法进行拦截
@Aspect
@Component //将文件引入到Spring容器里去
public class HttpAspect {
//写逻辑处理代码,我们希望在HTTP请求到方法之前就将他记录下来
//Before表示在方法执行之前就拦截下来。girlList(..)表示不管里边是什么都会被拦截
@Before("execution(public * com.demo.girl.controller.GirlController.girlList(..))")
public void log(){
System.out.println("**********");
}
@After("log()")
public void doAfter("execution(public * com.demo.girl.controller.GirlController.girlList(..))"){
System.out.println("after");
}
}
为简化代码,减少重复的代码多次写,可以利用@Pointcut注解,注解一个公用方法,在随后的After和Before中不再需要多次写,如下
@Pointcut("execution(public * com.demo.girl.controller.GirlController.*(..))")
public void log(){
System.out.println("Before");
}
public void doBefore(){
System.out.println("Before");
}
@After("log()")
public void doAfter(){
System.out.println("after");
}
此外,输出方法也可以由System.out.println(” “)通过
private final static Logger logger = LoggerFactory.getLogger((HttpAspect.class));
语句变成logger.info(“Before”);这样在打印时会将日志的详细信息都打印出来。
(4)将(3)的方法拦截输出变为对HTTP请求的拦截的输出,包括对URL,请求的方法,IP,类方法,参数的拦截,写在doBefore方法中,如下:
@Before("log()")
public void doBefore(JoinPoint joinPoint){ //传入joinPoint以拦截获取方法
/*System.out.println("Before");
logger.info("Before");*/
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//(ServletRequestAttributes强制转换)
HttpServletRequest request = attributes.getRequest();
//url
logger.info("url={}",request.getRequestURL());
//method
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());
}
结果为:
(5)将URL请求得到的数据库中的结果内容输出在控制台
在domain中的Girl.java中写入toString方法
@Override
public String toString() {
return "Girl{" +
"id=" + id +
", cs='" + cs + '\'' +
", age=" + age +
", money=" + money +
'}';
}
再在HttpAspect.java中写入如下方法,
//用来将URL请求得到的数据库中的内容输出在控制台
@AfterReturning(returning = "object",pointcut = "log()")//传入两个参数
public void doAfterReturening(Object object){
logger.info("response={}",object.toString());
}
结果在控制台打印出来
三、统一异常处理
1、添加女生信息时,对数据的非空性进行判断,如果数据正确,返回正确的信息,如果错误则返回错误的信息,信息包括错误码code,错误信息msg,错误的数据data,在domain包中定义Result.java,并加入get和set方法。
public class Result <T> {
/** 错误码.*/
private Integer code;
/** 提示信息.*/
private String msg;
/** 具体的内容 */
private T data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
再建立一个util的包,其中建立ResultUtil.java类,定义成功方法和错误时的方法
public class ResultUtil {
public static Result success(Object object){
Result result = new Result();
result.setCode(0);
result.setMsg("成功");
result.setData(object);
return result;
}
public static Result success(){
return success(null);
}
public static Result error(Integer code,String msg){
Result result = new Result();
result.setCode(code);
result.setMsg(msg);
return result;
}
}
然后在GirlController.java中添加女生信息处加入判断,成功时调用ResultUtil的成功success方法,错误则调用错误error方法.
@PostMapping(value = "/girls")
public Result<Girl> girlAdd(@Valid Girl girl, BindingResult bindingResult){
if (bindingResult.hasErrors()){
return ResultUtil.error(1,bindingResult.getFieldError().getDefaultMessage());
}
girl.setCs(girl.getCs());
girl.setAge(girl.getAge());
return ResultUtil.success(girlRepository.save(girl));
}
- 异常捕获,抛出异常
GirlServic.java中写逻辑判断,并抛出异常
public void getAge(Integer id) throws Exception{
Girl girl = girlRepository.findOne(id);
Integer age = girl.getAge();
if(age < 10){
//返回"你还在上小学 ";
throw new Exception("你还在上小学吧");
}else if(age > 10 && age < 16){
//返回"你可能在上初中 " ;
throw new Exception("你可能在上初中");
}
}
创建handle包,其中建立ExceptionHandle.java类,对异常进行捕获
@ControllerAdvice
public class ExceptionHandle {
@ExceptionHandler(value = Exception.class) //要捕获的类为Exception这个类
@ResponseBody
public Result handle(Exception e){ //由handle这个类来处理这些异常
return ResultUtil.error(100,e.getMessage());
}
}
此外,在GirlController中调用service时也要抛出异常。
@GetMapping(value = "girls/getAge/{id}")
public void getAge(@PathVariable("id") Integer id)throws Exception{
girlService.getAge(id);
}
3,为了使小于10岁和小于16岁抛出的异常的code不一样,有所区分,故自定义异常
创建exception包,其中创建GirlException.java
//RuntimeException继承自Exception,Spring框架只对抛出的异常是RuntimeException才会进行事务回滚,若为Exception不回事务回滚
public class GirlException extends RuntimeException {
private Integer code;
//写一个构造方法,传入两个参数
public GirlException(ResultEmum resultEmum){
super(resultEmum.getMsg());//父类的构造方法本身就会传一个message
this.code = resultEmum.getCode();
}
public Integer getCode() {
return code;
}
public void setCeode(Integer ceode) {
this.code = ceode;
}
}
4、 值得学习的是:为了统一管理错误的code,使用枚举统一管理code,和msg,所以创建emums包,在其中创建ResultEmum.java,注意创建的时候类型为枚举型不是类。在其中将其错位类型进行枚举,而且其中的code和msg只需要get方法即可,不需要set方法,因为已经在枚举里枚举了所有可能的类型。之后如第3步一样直接进行调用就可以了。这样的话方便以后修改时,直接修改一个地方就可以,不需要全文进行搜索进行修改。注意枚举时用的是逗号。
public enum ResultEmum
{
UNKNOM_ERROR(-1,"位置错误"),
SUCCESS(0,"成功"),
PRIMARY_SCHOOL(100,"你可能还在上小学"),
MIDDLE_SCHOOL(101,"你可能在还是那个初中"), ;
private Integer code;
private String msg;
ResultEmum (Integer code ,String msg){
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}