接口开发,至少面临以下问题: 接口文档、数据验证、 接口安全等等。
关于程序员讨厌写文档的原因,你懂的,程序员的大量精力都投入在接口的开发上,没有精力来撰写相关文档,可以工作的软件胜过面面俱到的文档!
关于数据验证,接触过一些项目,整个系统基本的数据校验都没有,一眼就能找出破绽使项目运行异常。
关于接口安全,完整的接口不仅要保证数据的可靠性,同时也要确保接口的安全性,哪些用户可以访问,哪些人不允许访问。
接口文档 swagger ui 解决你的烦恼,如何集成Swagger到项目中,之前文章已有详细说明 http://blog.csdn.net/dhweicheng/article/details/78160302
/**
*
* @ClassName SwaggerConfig
* @Description api 管理
* @author Cheng.Wei
* @date 2017年11月19日 下午9:29:25
*
*/
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket platformApi() {
return new Docket(DocumentationType.SWAGGER_2).groupName("DEMO").select().apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build().apiInfo(apiInfo())
.forCodeGeneration(true);
}
private static ApiInfo apiInfo() {
return new ApiInfoBuilder().title("测试接口").description("api文档")
.contact(new Contact("Cheng.Wei", "tencent://message/?uin=xxxxx", "[email protected]")).license("Apache License Version 2.0")
.licenseUrl("https://github.com/abelsilva/SwaggerWCF/blob/master/LICENSE").version("1.0").build();
}
}
参数验证 Bean Validation 集成:(Spring 4.3.5)添加hibernate validator 5依赖
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>
Spring MVC 配置
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
简单参数校验
接口分组
/**
* @ClassName RoleGroup
* @Description 角色验证分组 新增、更新
* @author Cheng.Wei
* @date 2017年11月19日 下午10:00:42
*
*/
public interface RoleGroup {
/**新增*/
public static interface Add{}
/**更新*/
public static interface Update{}
/***更具需要自定义更多*****/
}
对象验证规则( get 、set 省略 )
/**
* @ClassName Role
* @Description 角色
* @ApiModel 、 @ApiModelProperty 用来标记属性对应的名称,方便通过Swagger 查看接口文档参数
* @author Cheng.Wei
* @date 2017年11月19日 下午8:08:52
*
*/
@ApiModel("角色")
public class Role {
@Null(groups = RoleGroup.Add.class)
@NotNull(groups = RoleGroup.Update.class)
@Length(groups = RoleGroup.Update.class, min = 1, max = 10)
private String id;
@NotNull(groups = { RoleGroup.Add.class, RoleGroup.Update.class })
@Length(groups = { RoleGroup.Add.class, RoleGroup.Update.class }, min = 1, max = 10)
private String name;
}
控制器
/**
* @ClassName RoleController
* @Description 角色
* @author Cheng.Wei
* @date 2017年11月19日 下午10:03:30
* @see com.jsr.bean.group.RoleGroup 验证分组
* @see com.jsr.bean.Role 对象参数及分组情况
*/
@Controller
@RequestMapping(value = "/role")
public class RoleController extends BaseController{
@RequestMapping(method = RequestMethod.POST)
public ModelAndView add(@Validated(RoleGroup.Add.class) Role role, BindingResult bindingResult) {
logger.info(">>>>执行新增角色操作:{}", role);
/**
* TODO
*/
return getResultMav();
}
@RequestMapping(method = RequestMethod.PUT)
public ModelAndView update(@Validated(RoleGroup.Update.class) Role role, BindingResult bindingResult) {
logger.info(">>>>执行更新角色操作:{}", role);
/**
* TODO
*/
return getResultMav();
}
}
切面
/**
* @ClassName FormValidationAspect
* @Description 表单参数验证
* @author Cheng.Wei
* @date 2017年11月19日 下午10:45:20
*
*/
@Aspect
@Component
public class FormValidationAspect {
protected static final Logger logger = LogManager.getLogger(FormValidationAspect.class);
@Around(value = "@annotation(org.springframework.web.bind.annotation.RequestMapping)", argNames = "joinPoint")
public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
BindingResult result = null;
Object[] args = joinPoint.getArgs();
if (args != null && args.length != 0) {
for (Object object : args) {
if (object instanceof BindingResult) {
result = (BindingResult) object;
break;
}
}
}
if (result != null && result.hasErrors()) {
FieldError fieldError = result.getFieldError();
logger.info("参数验证失败.控制器:{}, 方法:{}, 属性:{}, 错误编码:{} >>> 消息:{}", joinPoint.getTarget().getClass().getSimpleName(), joinPoint.getSignature().getName(), fieldError.getField(), fieldError.getCode(),fieldError.getDefaultMessage());
ModelAndView mav = new ModelAndView("jsonView");
mav.addObject("code", -1);
mav.addObject("detail", fieldError.getField() + ":"+ fieldError.getDefaultMessage());
mav.addObject("msg", "数据提交异常");
return mav;
}
return joinPoint.proceed();
}
}
执行效果:
嵌套验证:
接口分组
/**
* @ClassName UserGroup
* @Description 用户分组验证
* @author Cheng.Wei
* @date 2017年11月19日 下午10:30:13
*
*/
public interface UserGroup {
/**新增*/
public static interface Add{}
/**更新*/
public static interface Update{}
/***更具需要自定义更多*****/
}
对象验证规则( get 、set 省略 ;用户 --书 一对多关系)
Book
/**
* @ClassName Book
* @Description 书本
* @author Cheng.Wei
* @date 2017年11月19日 下午10:26:37
*
*/
public class Book {
@NotNull(groups = { UserGroup.Add.class, UserGroup.Update.class })
@ApiModelProperty(name = "唯一标识")
private Integer id;
@NotBlank(groups = { UserGroup.Add.class, UserGroup.Update.class })
@Length(min = 1, max = 10, groups = { UserGroup.Add.class, UserGroup.Update.class })
@ApiModelProperty(name = "名称")
private String name;
}
User
/**
* @ClassName User
* @Description 人员
* @ApiModel 、 @ApiModelProperty 用来标记属性对应的名称,方便通过Swagger 查看接口文档参数
* @author Cheng.Wei
* @date 2017年11月19日 下午8:07:00
*
*/
@ApiModel("人员")
public class User {
@Null(groups = UserGroup.Add.class)
@NotBlank(groups = UserGroup.Update.class)
@ApiModelProperty(name = "标识")
private String id;
@NotBlank(groups = { UserGroup.Add.class, UserGroup.Update.class })
@Length(min = 2, max = 10, groups = { UserGroup.Add.class, UserGroup.Update.class })
@ApiModelProperty(name = "姓名")
private String name;
@Valid
private List<Book> book;
}
控制器
/**
*
* @ClassName UserController
* @Description 用户
* @author Cheng.Wei
* @date 2017年11月19日 下午8:05:39
* @see com.jsr.bean.group.UserGroup 接口验证分组
* @see com.jsr.bean.User 对象信息及分组
*/
@Controller
public class UserController extends BaseController{
@RequestMapping(value = "/user", method = RequestMethod.POST)
public ModelAndView add(@Validated(UserGroup.Add.class) @RequestBody User user, BindingResult bindingResult) {
logger.info(">>>>执行新增操作");
/**
*
* TODO
*/
return getResultMav();
}
@RequestMapping(value = "/user", method = RequestMethod.PUT)
public ModelAndView update(@Validated(UserGroup.Update.class) @RequestBody User user, BindingResult bindingResult) {
logger.info(">>>>执行更新操作");
/**
* TODO
*/
return getResultMav();
}
}
执行效果
至此,表单参数验证完成,权限验证方面spring security、 shiro 会在今后补充。