SpringBoot入门二
来源:互联网 发布:windows 2003安装ad域 编辑:程序博客网 时间:2024/06/05 20:40
SpringBoot入门二
表单验证
表单验证,就是对用户的输入数据进行有效性检查
例如在添加某个实体Girl时,要满足其年龄必须大于18岁,否则不能提交
此时可以对Girl的age属性,使用@Min
注解
@Min(value = 18, message = "年龄未满18岁") private Integer age;
同时对于添加数据的方法,需添加:
@Valid
- 表示验证的对象BindingResult
- 获取验证的结果
如下:
@PostMapping(value = "/girls") public Girl girlAdd(@Valid Girl girl, BindingResult bindingResult){ if (bindingResult.hasErrors()){ System.out.println(bindingResult.getFieldError().getDefaultMessage()); return null; } return girlReponsitory.save(girl); }
此时,如果我们添加一个age小于18
的对象,此时控制台会输出年龄未满18岁
其它验证注解,参考Spring Boot 表单验证篇
Bean Validation 规范,运行时的数据验证框架。它是 JSR 303 规范,Hibernate Validator 实现了这套规范,并扩展了一些注解,如下:
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Email 被注释的元素必须是电子邮箱地址
@Length 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range 被注释的元素必须在合适的范围内
AOP
AOP是一种编程范式,与语言无关,是一种编程设计思想。将通用逻辑从业务逻辑中分离出来
AOP统一处理请求日志
步骤:
1.在pom.xml
中添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2.创建处理文件HttpAspect
,添加@Aspect
、@Component
注解
@Aspect@Componentpublic class HttpAspect { @Before("execution(public * com.wz.girl.controller.GirlController.*(..))") public void logBefore(){ System.out.println("logBefore"); } @After("execution(public * com.wz.girl.controller.GirlController.*(..))") public void logAfter(){ System.out.println("logAfter"); }}
上面的代码中,execution(public * com.wz.girl.controller.GirlController.*(..))
是重复的,可以这样优化:
@Aspect@Componentpublic class HttpAspect { //表示切点 @Pointcut("execution(public * com.wz.girl.controller.GirlController.*(..))") public void log(){ } @Before("log()") public void logBefore(){ System.out.println("logBefore"); } @After("log()") public void logAfter(){ System.out.println("logAfter"); }}
此时,如果调用某个http://localhost:8083/girl/girls/1
,控制台会输出:
logBeforeHibernate: select girl0_.id as id1_0_0_, girl0_.age as age2_0_0_, girl0_.cup_size as cup_size3_0_0_ from girl girl0_ where girl0_.id=?logAfter
3.使用日志输出
@Aspect@Componentpublic class HttpAspect { private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class); //表示切点 @Pointcut("execution(public * com.wz.girl.controller.GirlController.*(..))") public void log(){ } @Before("log()") public void logBefore(){ logger.info("logBefore"); } @After("log()") public void logAfter(){ logger.info("logAfter"); }}
此时输出日志的形式为:
2017-11-15 21:23:03.582 INFO 63856 --- [nio-8083-exec-1] com.wz.girl.aspect.HttpAspect : logBeforeHibernate: select girl0_.id as id1_0_0_, girl0_.age as age2_0_0_, girl0_.cup_size as cup_size3_0_0_ from girl girl0_ where girl0_.id=?2017-11-15 21:23:03.683 INFO 63856 --- [nio-8083-exec-1] com.wz.girl.aspect.HttpAspect : logAfter
4.记录Http请求
@Before("log()") public void logBefore(JoinPoint joinPoint){ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 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()); } //获取返回的内容 @AfterReturning(returning = "object", pointcut = "log()") public void doAfterReturning(Object object){ logger.info("response={}", object); }
有某一个请求时,控制台输出为:
2017-11-15 21:38:26.536 INFO 64813 --- [nio-8083-exec-1] com.wz.girl.aspect.HttpAspect : url=http://localhost:8083/girl/girls/12017-11-15 21:38:26.537 INFO 64813 --- [nio-8083-exec-1] com.wz.girl.aspect.HttpAspect : method=GET2017-11-15 21:38:26.537 INFO 64813 --- [nio-8083-exec-1] com.wz.girl.aspect.HttpAspect : ip=0:0:0:0:0:0:0:12017-11-15 21:38:26.539 INFO 64813 --- [nio-8083-exec-1] com.wz.girl.aspect.HttpAspect : class_method=com.wz.girl.controller.GirlController.girlFindOne2017-11-15 21:38:26.539 INFO 64813 --- [nio-8083-exec-1] com.wz.girl.aspect.HttpAspect : args=1Hibernate: select girl0_.id as id1_0_0_, girl0_.age as age2_0_0_, girl0_.cup_size as cup_size3_0_0_ from girl girl0_ where girl0_.id=?2017-11-15 21:38:26.627 INFO 64813 --- [nio-8083-exec-1] com.wz.girl.aspect.HttpAspect : logAfter2017-11-15 21:38:26.627 INFO 64813 --- [nio-8083-exec-1] com.wz.girl.aspect.HttpAspect : response=Girl{id=1, cupSize='C', age=20}
统一异常处理
现在假设返回统一格式的信息,如下结构所示:
{ "code": 0, "msg": "成功", "data": { "id": 6, "cupSize": "D", "age": 18 }}
所以先需要定义一个Result
类,来表示返回的结果:
public class Result<T> { //错误码 private Integer code; //错误信息 private String msg; //数据 private T data; //getter setter方法 .....}//Result工具类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; }}
但如果调用某个方法抛出了某个异常,此时返回的数据格式,可能就会如下:
{ "timestamp": 1510755505374, "status": 404, "error": "Not Found", "exception": "java.lang.Exception", "message": "你可能还在上小学", "path": "/girl/girls/getAge/4"}
由此可见,需要一种统一处理异常的方式,来返回相同格式的数据,示例如下:
1.创建一个枚举,对应错误码和错误信息
public enum ResultEnum { UNKONW_ERROR(-1, "未知错误"), SUCCESS(0, "成功"), PRIMARY_SCHOOL(100, "你可能还在上小学"), MIDDLE_SCHOOL(101, "你可能在上中学") ; private Integer code; private String msg; ResultEnum(Integer code, String msg){ this.code = code; this.msg = msg; } public Integer getCode() { return code; } public String getMsg() { return msg; }}
2.自定义一个GirlException
异常类,Spring只会捕捉RuntimeException
异常,所以要继承RuntimeException
public class GirlException extends RuntimeException{ private Integer code; public GirlException(ResultEnum resultEnum) { super(resultEnum.getMsg()); this.code = resultEnum.getCode(); } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; }}
3.在某个方法抛出异常
public void getAge(Integer id) throws Exception{ Girl girl = girlReponsitory.findOne(id); Integer age = girl.getAge(); if (age < 10){ throw new GirlException(ResultEnum.PRIMARY_SCHOOL); }else if(age > 10 && age < 16){ throw new GirlException(ResultEnum.MIDDLE_SCHOOL); } }
4.新建一个异常处理类ExceptionHandle
,捕获异常,返回自定义结果。在这里统一处理异常
@ControllerAdvicepublic class ExceptionHandle { private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class); @ExceptionHandler(value = GirlException.class) @ResponseBody public Result handler(Exception e){ if (e instanceof GirlException){ GirlException girlException = (GirlException) e; return ResultUtil.error(girlException.getCode(), e.getMessage()); } logger.error("[系统异常]{}", e); return ResultUtil.error(-1, "位置错误"); }}
@ControllerAdvice
注解用来处理异常:
- Spring中添加@ControllerAdvice增强Controller
- Spring:异常统一处理的三种方式与Rest接口异常的处理
- 使用Spring MVC的@ControllerAdvice注解做Json的异常处理
5.此时,如果调用某个接口抛出了异常,则会返回如下结构的json数据:
{ "code": 101, "msg": "你可能在上中学", "data": null}
单元测试
参考:
- SpringBoot单元测试
- Spring Boot构建RESTful API与单元测试
Service测试
Service测试,需添加@RunWith(SpringRunner.class)
,@SpringBootTest
注解
@RunWith(SpringRunner.class)@SpringBootTestpublic class GirlServiceTest { @Autowired private GirlService girlService; @Test public void findOneTest(){ Girl girl = girlService.findOne(1); Assert.assertEquals(new Integer(20), girl.getAge()); }}
Controller测试
创建单元测试还可以右键,有IDE来生成单元测试类:
需额外添加@AutoConfigureMockMvc
注解
@RunWith(SpringRunner.class)@SpringBootTest@AutoConfigureMockMvcpublic class GirlControllerTest { @Autowired private MockMvc mvc; @Test public void girlList() throws Exception { mvc.perform(MockMvcRequestBuilders.get("/girls")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().string("abc")); }}
其它
教程:
- Spring Boot进阶之Web进阶
- SpringBoot入门(二)
- SpringBoot入门二
- SpringBoot简单入门(二)
- SpringBoot简单入门(二)
- springboot入门(二)--springboot常用注解及配置
- springboot入门(二)初步集成mybatis
- springboot学习(二) Spring Boot 快速入门
- Springboot入门(二)项目配置
- SpringBoot学习(二)——入门
- SpringBoot的入门搭建(二)
- SpringBoot入门
- springboot入门
- springboot 入门
- springboot 入门
- SpringBoot入门
- SpringBoot入门
- SpringBoot入门
- Springboot入门
- 数据库分组统计
- 行列式求解【线性代数】
- JMeterPlugin 部分说明
- Linux
- 设计模式-创建模式之Abstract Factory
- SpringBoot入门二
- 爬虫Scrapy-01框架介绍
- ajax判断远程服务器是否存在某文件
- CodeForces
- mybatis环境的搭建(使用案例)
- C++ Brute Force算法
- Java程序通过JDBC-ODBC连接本地数据库
- 【数字图像处理】SIFT算法详解
- a1~2