跳至主要內容

web-starter 使用说明

Mr.Vincent大约 12 分钟开发指引web

该组件作为web通用组件使用,可引入web项目模块中,目前仅添加swagger-starter功能,后续会添加关于web的其他功能。

一、swagger

1、使用说明

在pom.xml中引入依赖:

<dependency>
    <groupId>com.pcitc.si</groupId>
    <artifactId>common-web-starter</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

2、应用配置说明

属性字段是否必填默认值说明
swagger.enablefalse是否开启swagger,如生产环境可设置为false
swagger.api-info.description应用程序的简短描述。
swagger.api-info.title应用程序的名称。
swagger.api-info.version提供应用程序API的版本 如 1.0.0
swagger.api-info.contact.name公开的API的联系信息。
swagger.api-info.contact.email联系人/组织的电子邮件地址。 必须采用电子邮件地址的格式。
swagger.docket.base-package---扫描的路径 一帮配置controller包路径

配置示例 在application.yml中添加如下配置

swagger:
    enable: true    #是否开启swagger/默认false
    docket:
    base-package: com.pcitc.si.business #扫描的路径/基本就是你的controller包下面
    #注:最简配置,如需其他配置项请参考应用配置说明。

3、注解使用说明

@Api()

用于类;表示标识这个类是swagger的资源
tags–表示说明
value–也是说明,可以使用tags替代
但是tags如果有多个值,会生成多个list
@Api(value="用户controller",tags={"用户操作接口"})
@RestController
public class UserController {
}

@ApiOperation()

 用于方法;表示一个http请求的操作
value用于方法描述
notes用于提示内容
tags可以重新分组(视情况而用)

例:

@Api(value="用户controller",tags={"用户操作接口"})
@RestController
public class UserController {

@ApiOperation(value="获取用户信息",tags={"获取用户信息"},notes="注意问题点")
@GetMapping("/getUserInfo")
public User getUserInfo(@ApiParam(name="id",value="用户id",required=true) Long id,@ApiParam(name="username",value="用户名") String username) {
// userService可忽略,是业务逻辑
User user = userService.getUserInfo();
return user;
}
}

@ApiModel()

用于类 ;表示对类进行说明,用于参数用实体类接收
value–表示对象名
description–描述
都可省略

@ApiModelProperty()

用于方法,字段; 表示对model属性的说明或者数据操作更改
value–字段说明
name–重写属性名字
dataType–重写属性类型
required–是否必填
example–举例说明
hidden–隐藏

例:

    @ApiModel(value="user对象",description="用户对象user")
    public class User implements Serializable{
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value="用户名",name="username",example="xingguo")
    private String username;
    @ApiModelProperty(value="状态",name="state",required=true)
    private Integer state;
    @ApiModelProperty(value="是否删除",hidden=true)
    private Integer isDeleted;
    //省略get/set
    }

@ApiIgnore()

用于类或者方法上,可以不被swagger显示在页面上

@ApiImplicitParam()

表示单独的请求参数

@ApiImplicitParams()

用于方法,包含多个 @ApiImplicitParam
name–参数ming
value–参数说明
dataType–数据类型
paramType–参数类型
example–举例说明

例:

@Api(value="用户controller",tags={"用户操作接口"})
@RestController
public class UserController {

@ApiOperation(value="获取用户信息",tags={"获取用户信息"},notes="注意问题点")
@ApiImplicitParams({
@ApiImplicitParam(name="id",value="用户id",dataType="long", paramType = "query"),
@ApiImplicitParam(name="username",value="用户名",dataType="string", paramType = "query",example="xxx")
})
@GetMapping("/getUserInfo")
public User getUserInfo( Long id, String username) {
// userService可忽略,是业务逻辑
User user = userService.getUserInfo();
return user;
}
}

4、访问地址

http://${host}:${port}/swagger-ui.html


二、 表格导出excel

1.后台配置

该功能使用aop切面编程实现。支持在翻页查询方法上增强导出功能

导入依赖

<dependency>
            <groupId>com.pcitc.si</groupId>
            <artifactId>common-web-starter</artifactId>
            <version>1.0.0-SNAPSHOT</version>
 </dependency>

在翻页查询方法上添加注解 com.pcitc.si.common.core.annotation.Export ,返回值类型需要使用 Result<ResultPage> 使用get请求方法 如

@ApiOperation("分页查询菜单收藏")
@GetMapping("/101091003")
@Export
public Result<ResultPage> findList(@RequestParam(Constants.PAGE_NUM_STR) Integer pageNum,
                                    @RequestParam(Constants.PAGE_SIZE_STR) Integer pageSize, MenuQuickBo menuQuickBo) {
    return menuQuickService.getListByPage(pageSize, pageNum, menuQuickBo);
}

2.前端配置

请求翻页查询接口导出 ,需要添加参数

export:ture ,

columns:"[{'key':'对象字段','name‘:’列名称‘},{’key‘:’userCode‘,’name‘:’列名称2‘}]"

filename:filename

pageNum:1, pageSize:5

上面加粗的参数为导出请求扩展参数,如下为字段描述说明

export: 表示该请求为导出操作

columns:导出的字段描述(json字符串格式)

filename:导出文件名

columns配置说明

字符型 : {'key':'对象字段','name‘:’列名称‘}

编码转中文:{'key':'对象字段','name‘:’列名称‘,valueAlias:[{1:"是",0:"否"}]}

数字: {'key':'对象字段','name‘:’列名称‘,number:{pattern:".000000",scale:6}}

pattern 可参考如下地址配置。

https://www.mianshigee.com/tutorial/hutool/1ac79ebaf52a0372.md

三、系统操作日志

  1. 说明

该功能为记录系统用户操作日志功能。需要开发人员使用注解添加到controller方法上,添加方法描述,才能被日志功能采集用户请求行为

注解:com.pcitc.si.common.core.annotation.MethodLog

如下

@ApiOperation("分页查询菜单收藏")
@GetMapping("/101091003")
@MethodLog(desc = "分页查询菜单收藏")
public Result<ResultPage> findList(@RequestParam(Constants.PAGE_NUM_STR) Integer pageNum,
                                   @RequestParam(Constants.PAGE_SIZE_STR) Integer pageSize, MenuQuickBo menuQuickBo) {
    return menuQuickService.getListByPage(pageSize, pageNum, menuQuickBo);
}

该功能默认记录使用log日志记录到日志文件中,后续日志会集成到elk中,如项目需要记录行为日志到其他地方。如mysql中,可以在项目中实现LogServer 接口。

如下

public class LogServerImpl extends LogServer {

    @DubboReference
    UserLogService userLogService;
 
    @Override
    public Result storage(MethodLogEntity methodLogEntity) {
        UserLogBo userLogBo=new UserLogBo();
        userLogBo.setId(methodLogEntity.getId());
        userLogBo.setCreateDate(new DateTime());
        userLogBo.setDescription(methodLogEntity.getDesc());
        userLogBo.setIp(methodLogEntity.getIp());
        userLogBo.setUserCode(methodLogEntity.getUserId());
        userLogBo.setUrl(methodLogEntity.getReqUri());
        userLogBo.setUrlParams(methodLogEntity.getReqParam());
        userLogBo.setSourceType("");
        return userLogService.insertLog(userLogBo);
    }
}

四、添加表单验证

应用程序的业务逻辑中,经常会碰到参数校验的情况,比如在Controller中,我们的参数是一个Entity的时候,经常要判断这个Entity的字段是否是null之类或者是长度等。通常来讲,我们用比如StringUtils或者是if等来进行校验,这样在我们的代码层上面就会带来很不好的体验,阅读、维护的成本会大大增加,造成冗余。因此有了这个JSR 303。

Bean Validation为JavaBean提供了相应的API来给我们做参数的验证。通过Bean Validation比如@NotNull @Pattern等方法来对我们字段的值做进一步的校验。

1.相关的注解

img

表单验证注解

@AssertFalse用于boolean字段,该字段只能为true
@AssertFalse用于boolean字段,该字段只能为false
@DecimalMax(value=x)验证注解的元素值小于等于@ DecimalMax指定的value值
@DecimalMin(value=x)验证注解的元素值大于等于@ DecimalMin指定的value值
@Digits(integer=整数位数, fraction=小数位数)限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Email验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
@Future(integer=整数位数, fraction=小数位数)验证注解的元素值(日期类型)比当前时间晚
@FutureOrPresent(integer=整数位数, fraction=小数位数)验证注解的元素值(日期类型)比当前时间晚或者等于当前时间
@Past验证注解的元素值(日期类型)比当前时间早
@PastOrPresent验证注解的元素值(日期类型)比当前时间早或等于现在
@Max(value=x)验证注解的元素值小于等于@Max指定的value值
@Mix(value=x)验证注解的元素值大于等于@Max指定的value值
@NotBlank验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@NotEmpty验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotNull验证注解的元素值不是null
@Null验证注解的元素值是null
@Pattern(regex=正则表达式, flag=)验证注解的元素值与指定的正则表达式匹配
@Size(min=最小值, max=最大值)验证注解的元素值的在min和max(包含)指定区间之内,如字符长度、集合大小
@Pattern被注释的元素必须符合指定的正则表达式
@Email元素必须是格式良好的电子邮箱地址
@Length(min=最小值, max=最大值)字符串的大小必须在指定的范围内,有min和max参数
@NotEmpty字符串的不能是空
@NotBlank字符串不能使空,但是与@NotEmpty不同的是尾随的空白被忽略
@URL    字符串必须是一个URL
@Valid递归的对关联对象进行校验, 如果关联对象是个集合或者数组, 那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验
@Range(min, max)被注释的元素必须在合适的范围内 (主要用于 : BigDecimal, BigInteger, String, byte, short, int, long ,原始类型的包装类 )

在表达的接收对象加上对应的验证注解 ,如

@Data
public class ValidationParam {
   @NotNull(message = "用户名不能为空")
   String username;@NotBlank(message = "手机号码不能为空")
   String phone;@NotBlank(message = "身份证不能为空")
   String idCard;
}

接口在接收参数的时候,加上 @Valid 注解,指定这个参数需要进行校验

@RestController
@RequestMapping("/ValidationResultTest")
public class ValidationController {
   @PostMapping
    public String ValidationResultTest(@Valid @RequestBody ValidationParam validationParam) {
       return "success";
    }
}

验证结果 不通过会由全局异常处理,并封装返回前端。不用做额外处理。

2.@Validated和@Valid区别

Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's JSR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。其中对于字段的特定验证注解比如@NotNull等网上到处都有,这里不详述

在检验Controller的入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同:

  1. 分组

@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制,这个网上也有资料,不详述。@Valid:作为标准JSR-303规范,还没有吸收分组的功能。

  1. 注解地方

@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上

@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上

两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能。

  1. 嵌套验证

在比较两者嵌套验证时,先说明下什么叫做嵌套验证。比如我们现在有个实体叫做Item:

public class Item {

    @NotNull(message = "id不能为空")
    @Min(value = 1, message = "id必须为正整数")
    private Long id;

    @NotNull(message = "props不能为空")
    @Size(min = 1, message = "至少要有一个属性")
    private List<Prop> props;
}
 

Item带有很多属性,属性里面有属性id,属性值id,属性名和属性值,如下所示:

public class Prop {

    @NotNull(message = "pid不能为空")
    @Min(value = 1, message = "pid必须为正整数")
    private Long pid;

    @NotNull(message = "vid不能为空")
    @Min(value = 1, message = "vid必须为正整数")
    private Long vid;

    @NotBlank(message = "pidName不能为空")
    private String pidName;

    @NotBlank(message = "vidName不能为空")
    private String vidName;
}
 

属性这个实体也有自己的验证机制,比如属性和属性值id不能为空,属性名和属性值不能为空等。

现在我们有个ItemController接受一个Item的入参,想要对Item进行验证,如下所示:

@RestController public class ItemController {

    @RequestMapping("/item/add")
    public void addItem(@Validated Item item, BindingResult bindingResult) {
        doSomething();
    }
    }

在上图中,如果Item实体的props属性不额外加注释,只有@NotNull@Size,无论入参采用@Validated还是@Valid验证,Spring Validation框架只会对Item的id和props做非空和数量验证,不会对props字段里的Prop实体进行字段验证,也就是@Validated和@Valid加在方法参数前,都不会自动对参数进行嵌套验证。也就是说如果传的List<Prop> 中有Prop的pid为空或者是负数,入参验证不会检测出来。

为了能够进行嵌套验证,必须手动在Item实体的props字段上明确指出这个字段里面的实体也要进行验证。由于@Validated不能用在成员属性(字段)上,但是@Valid能加在成员属性(字段)上,而且@Valid类注解上也说明了它支持嵌套验证功能,那么我们能够推断出:@Valid加在方法参数时并不能够自动进行嵌套验证,而是用在需要嵌套验证类的相应字段上,来配合方法参数上@Validated或@Valid来进行嵌套验证。

我们修改Item类如下所示:

public class Item {

    @NotNull(message = "id不能为空")
    @Min(value = 1, message = "id必须为正整数")
    private Long id;

    @Valid // 嵌套验证必须用@Valid
    @NotNull(message = "props不能为空")
    @Size(min = 1, message = "props至少要有一个自定义属性")
    private List<Prop> props;
}
 

然后我们在ItemController的addItem函数上再使用@Validated或者@Valid,就能对Item的入参进行嵌套验证。此时Item里面的props如果含有Prop的相应字段为空的情况,Spring Validation框架就会检测出来,bindingResult就会记录相应的错误。

总结一下@Validated和@Valid在嵌套验证功能上的区别:

@Validated:用在方法入参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

@Valid:用在方法入参上无法单独提供嵌套验证功能。能够用在成员属性(字段)上,提示验证框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。