1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【Java从0到架构师】项目实战 - 前后端分离 后端校验 Swagger 全局异常处理

【Java从0到架构师】项目实战 - 前后端分离 后端校验 Swagger 全局异常处理

时间:2022-04-03 03:53:39

相关推荐

【Java从0到架构师】项目实战 - 前后端分离 后端校验 Swagger 全局异常处理

项目实战 - 前后端分离、后端校验、Swagger

Layui同源策略SpringMVC 实现 CORS后端校验 - hibernate-validator方法的 Model 参数校验方法的非 Model 参数校验常见注解自定义校验快速失败Swagger基本配置与使用常用注解Bug:NumberFormatException全局异常处理驾考 - 前后端分离MyBatis 的 QueryWrapper 的增强实现mapstruct前后端分离使用 Session企业中的文件上传(图片、视频)

Java 从 0 到架构师目录:【Java从0到架构师】学习记录

驾考系统 Gitee 代码(前端 + 后端):/szluyu99/jiakao

早期的前后端协作模式:

前端:切图仔、页面仔后台:动态模板技术组装成

以前的协作模式的问题:

前端地位比较低,大部分工作都在后台调试、修改页面比较麻烦,需要前端、后台充分配合浪费流量(每次请求都会返回整个页面,这就意味着返回了很多重复的内容)

前后端分离:

前端:切图、页面、交互、路由、业务逻辑后台:返回 JSON

前后端分离:

页面保持使用静态页面即可(html)静态页面(浏览器)发送异步请求(AJAX)给服务器,服务器返回 JSON浏览器解析 JSON 数据,动态生成对应的 HTML 标签,显示到用户眼前前端一个项目、后端一个项目,分开开发(跨域)前端一个服务器、后端一个服务器,分开部署

Layui

Layui 是一款前端 UI 框架,可以帮助开发者快速搭建后台管理系统的前端页面

免费版:/LayuiMini(更强大的免费版):/

本课程使用的是单页版:v2-onepage

基本使用:下载后解压,将以下内容放到项目中

同源策略

浏览器有个同源策略 (Same-Origin Policy)

它规定了:默认情况下,AJAX请求只能发给同源的URL同源是指3个相同:协议、域名(IP)、端口

img、script、link、iframe、video、audio 等标签不受同源策略的约束

解决 AJAX 跨域请求的常用方法:

CORS (Cross-Origin Resource Sharing),跨域资源共享

CORS 的实现需要客户端和服务器同时支持:

客户端:基本所有的浏览器都支持(IE 至少是 IE10 版本)服务器:需要返回相应的响应头(比如 Access-Control-Allow-Origin),告知浏览器这是一个允许跨域的请求

Access-Control-Allow-Origin 用于允许跨域。

如果不设置允许跨域,则会出现下面情况:

在返回响应时要设置允许跨域,即可跨域访问资源。

设置跨域后,即可成功访问页面。

SpringMVC 实现 CORS

局部设置:在某个 Controller 上使用@CrossOrigin注解,允许当前 Controller 被跨域访问

@RequestMapping("/plateRegions")@CrossOrigin("http://localhost:63342")public class PlateRegionController {}

全局设置

需要客户端设置后才会发送 Cookie

let xhr = new XMLHttpRequest()xhr.withCredentials = true

服务器设置:

@Configurationpublic class WebCfg implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {// /**表示对所有的路径开放全局跨域访问权限registry.addMapping("/**")// 开放哪些IP、端口、域名的访问权限.allowedOrigins("*")// 是否允许发送Cookie信息.allowCredentials(true)// 哪些HTTP方法允许跨域访问.allowedMethods("GET", "POST");// 允许HTTP请求中携带的哪些Hedaer信息.allowHeaders("*");// 暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)// .exposeHeaders("*");}}

后端校验 - hibernate-validator

前端哪怕页面上的交互做好了校验,但是仍然可以通过 postman 等工具直接发送请求,因此前端校验是可以被跳过的,因此后端也应当有校验的功能;但是如果直接在 Controller 中写,又会增加大量代码,使得控制层十分的冗余,因此可以借助一些便利的框架来做后端校验。

hibernate-validator 是 Java 中常用的一款后端校验框架:

参考文档:

/hibernate/stable/validator/reference/en-US/html_single/

/hibernate/stable/validator/reference/en-US/pdf/hibernate_validator_reference.pdf

<!-- 后端校验 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>

方法的 Model 参数校验

使用步骤:

① 在 Model 的 getter 或成员变量上加相关的校验注解

@NotBlank(message = "名称不能为空")private String name;@NotBlank(message = "车牌不能为空")private String plate;

② 在 Model 参数上加@Valid注解

@PostMapping("/save")public R save(@Valid T entity) {if (getService().saveOrUpdate(entity)) {return Rs.ok(CodeMsg.SAVE_SUCCESS);} else {return Rs.raise(CodeMsg.SAVE_ERROR);}}

校验失败时,会抛出异常:org.springframework.validation.BindException

可以通过 BindException.getBindResult().getAllErrors() 拿到所有的错误信息

方法的非 Model 参数校验

使用步骤:

① 在 Controller 上加@Validated注解

② 在非 Model 参数上加相关的校验注解

@Validatedpublic abstract class BaseController<T> {@PostMapping("/remove")public R remove(@NotBlank(message = "id不能为空") String id) {// code...}}

校验失败时,会抛出异常:javax.validation.ConstraintViolationException

可以通过 ConstraintViolationException.getConstraintViolations() 拿到所有的错误信息

常见注解

@NotNull:不能为 null,但可以为 empty

@NotEmpty:不能为 null,而且长度必须大于 0

@NotBlank:只能作用在 String 上,不能为 null,且去除空格后长度必须大于 0

@AssertFalse:必须为 false

@AssertTrue:必须为 true

@Max,@DecimalMax:必须为一个不大于指定值的数字

@Min,@DecimalMin:必须为一个不小于指定值的数字

@Digits:必须为一个小数,且整数部分的位数不能超过 integer,小数部分的位数不能超过 fraction

@Email:必须是 Email,也可以通过正则表达式和 flag 指定自定义的 Email 格式

@Future:必须是一个将来的日期

@Past:必须是一个过去的日期

@Range:必须在合适的范围内,min 到 max 之间

@Size,@Length:长度必须在 min 到 max 之间

@Pattern:必须符合指定的正则表达式

自定义校验

示例代码:自定义校验

@Documented@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy = BoolNumber.BoolNumberValidator.class)public @interface BoolNumber {// 这3个方法必须实现,不然会报错String message() default "只能是0和1";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};class BoolNumberValidator implements ConstraintValidator<BoolNumber, Short> {@Overridepublic boolean isValid(Short num, ConstraintValidatorContext constraintValidatorContext) {return num == null || num == 0 || num == 1;}}}

@BoolNumber(message = "disabled只能是0或1")private Short disabled;

快速失败

默认情况下是检测完所有的错误后再统一抛出异常,也可以设置快速失败

快速失败:只要检测到一个错误,就直接抛出异常,不再往下检查

@Configurationpublic class ValidatorCfg {@Beanpublic Validator validator() {return Validation.byProvider(HibernateValidator.class).configure().failFast(true) // 快速失败.buildValidatorFactory().getValidator();}}

Swagger

Swagger 可以快速生成接口文档,极大地节省了开发人员编写接口文档的时间

<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>3.0.0</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>3.0.0</version></dependency>

也可以使用官方的 starter 一步到位:

<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency>

基本配置与使用

代码:Swagger 的配置与使用

注:如果使用 starter,需要去掉@EnableSwagger2

@Configuration@EnableSwagger2 // 如果使用的 starter, 需要去掉这个注解public class SwaggerCfg {@Beanpublic Docket docket(Environment environment) {boolean enable = environment.acceptsProfiles(Profiles.of("dev", "test"));return new Docket(DocumentationType.SWAGGER_2).enable(enable).apiInfo(apiInfo());}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("驾考接口接口文档").description("已经包含了所有可用的请求接口").version("1.0.0").build();}}

配置好后,可以通过 URL 去访问 Swagger 文档页面,访问路径

如果使用了 starter:context_path/swagger-ui/index.html如果没有使用 swagger:context_path/swagger-ui.html

被 Swagger 显示的 API 应当由我们自己来配置,API 选择

以 dict 开头的包下的所有的接口:

new Docket(DocumentationType.SWAGGER_2).select().paths(PathSelectors.ant("/dict*/**")).build();

使用了@RestController注解的接口:

new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.withClassAnnotation(RestController.class)).build();

指定包下面的所有接口:

new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage("com.mj.jk.controller")).build();

有时候某些参数不希望显示出来被其他人看见,可以配置忽略参数

new Docket(DocumentationType.SWAGGER_2).ignoredParameterTypes(HttpSession.class,HttpServletRequest.class,HttpServletResponse.class);

可以将 API分组后进行显示(根据下拉框选择某个分组,展示对应的 API),例如:将满足条件的 API 接口配置到 “元数据” 这一组:

new Docket(DocumentationType.SWAGGER_2).groupName("元数据").select().paths(PathSelectors.regex("/(dict.+|plateRegions.+)")).build();

全局参数

Parameter token = new ParameterBuilder().name("token").description("用户登录令牌").parameterType("header") // 还可以是query.modelRef(new ModelRef("String")) // 参数类型.required(true) // 是否必要.build();new Docket(DocumentationType.SWAGGER_2).globalOperationParameters(List.of(token)); // List.of是jdk11的语法

常用注解

Bug:NumberFormatException

在使用 Swagger 2.9.2 版本时,可能经常在控制台看到一个异常:

java.lang.NumberFormatException:For input string:""这是 io.swagger:swagger-models:1.5.20 内部的一个 Bug升级到最新版本的 io.swagger:swagger-models 即可解决问题

直接在 pom.xml 中,使用下面的 io.swagger 则会覆盖 starter 中的版本

<dependency><groupId>io.swagger</groupId><artifactId>swagger-models</artifactId><version>1.6.2</version></dependency>

全局异常处理

@RestControllerAdvice@Slf4jpublic class CommonExceptionHandler {@ExceptionHandler(Throwable.class)@ResponseStatus(code = HttpStatus.BAD_REQUEST)public JsonVo handle(Throwable t) {log.error("handleThrowable", t);return null;}}

驾考 - 前后端分离

MyBatis 的 QueryWrapper 的增强实现

使用原生的 MyBatis 对于多个关键字的模糊查询写法比较累赘,对使用方法进行增强:

public class MpLambdaQueryWrapper<T> extends LambdaQueryWrapper<T> {// 返回值返回自身实现链式编程@SafeVarargspublic final MpLambdaQueryWrapper<T> like(Object val, SFunction<T, ?>... funcs) {if (val == null) return this;String str = val.toString();if (str.length() == 0) return this;return (MpLambdaQueryWrapper<T>) nested((w) -> {for (SFunction<T, ?> func : funcs) {w.like(func, str).or();}});}}

增强后,使用起来就很方便:

// 查询条件MpLambdaQueryWrapper<DictType> wrapper = new MpLambdaQueryWrapper<>();// 根据关键字查询wrapper.like(query.getKeyword(),DictType::getName,DictType::getValue,DictType::getIntro);

mapstruct

参考文章:mapstruct 使用详解

前后端分离使用 Session

后台:

allowCredentials(true)allowedOrigins(origins):origins 要指定特定主机地址,不能使用 *

前端:

$.ajax({url: url,xhrFields: {withCredentials: true}})

企业中的文件上传(图片、视频)

1、文件数据跟随表单数据一起提交

2、文件数据先单独提交,从文件服务器获取一个文件的 uri,文件的 uri 跟随表单数据一起提交

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。