├── .gitignore ├── README.md ├── images └── swagger.png ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── yisu │ │ ├── ApiApplication.java │ │ ├── common │ │ ├── constant │ │ │ └── FwCommonConstants.java │ │ ├── exception │ │ │ ├── ControllerExceptionHandler.java │ │ │ └── ValidateException.java │ │ ├── result │ │ │ └── FwResult.java │ │ └── validate │ │ │ ├── aop │ │ │ └── FwValidate.java │ │ │ └── aspect │ │ │ └── FwValidateAsprct.java │ │ ├── config │ │ └── swagger2 │ │ │ └── SwaggerConfig.java │ │ └── restful │ │ ├── controller │ │ └── UserController.java │ │ ├── data │ │ └── DataMock.java │ │ ├── entity │ │ └── User.java │ │ └── service │ │ ├── UserService.java │ │ └── impl │ │ └── UserServiceImpl.java └── resources │ ├── application.yml │ └── logback-spring.xml └── test └── java └── com └── yisu └── mock └── UserControllerTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | /.classpath 2 | /.factorypath 3 | /.project 4 | /.settings/ 5 | /target/ 6 | /log/ 7 | /.idea/ 8 | .idea/* 9 | *.iml 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 项目名restfu-api-demo 2 | 3 | #### 基于 Spring Boot 2.1.6.RELEASE 4 | 5 | ## 介绍 6 | 7 | 8 | >RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义。RESTFUL适用于移动互联网厂商作为业务使能接口的场景,实现第三方OTT调用移动网络资源的功能,动作类型为新增、变更、删除所调用资源 9 | 10 | # 注意事项 11 | ### 1.maven 依赖 12 | ```maven 13 | 14 | 15 | org.springframework.cloud 16 | spring-cloud-dependencies 17 | ${spring-cloud.version} 18 | pom 19 | import 20 | 21 | 22 | 23 | org.apache.commons 24 | commons-lang3 25 | ${commons-lang3.version} 26 | 27 | 28 | org.projectlombok 29 | lombok 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-test 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-aop 42 | 43 | 44 | org.springframework.data 45 | spring-data-commons 46 | ${data-commons.version} 47 | 48 | 49 | 50 | commons-io 51 | commons-io 52 | ${commons-io.version} 53 | 54 | 55 | commons-lang 56 | commons-lang 57 | ${commons-lang.version} 58 | 59 | 60 | commons-collections 61 | commons-collections 62 | ${commons-collections.version} 63 | 64 | 65 | commons-beanutils 66 | commons-beanutils 67 | ${commons-beanutils.version} 68 | 69 | 70 | 71 | 72 | io.springfox 73 | springfox-swagger2 74 | ${swagger.version} 75 | 76 | 77 | io.springfox 78 | springfox-swagger-ui 79 | ${swagger.version} 80 | 81 | 82 | 83 | cn.hutool 84 | hutool-all 85 | ${hutool.version} 86 | 87 | ``` 88 | 89 | ### 2.分组校验 90 | 实体类定义如下: 91 | ```java 92 | public class User implements Serializable { 93 | private static final long serialVersionUID = 1838417777538323571L; 94 | 95 | //主键 96 | @NotNull(message = "主键不能为空",groups =Update.class) 97 | private Long id; 98 | //用户名 99 | @NotNull(message = "用户名不能为空") 100 | private String userName; 101 | //密码 102 | @NotNull(message = "密码不能为空") 103 | private String password; 104 | //性别 105 | @NotNull(message = "性别不能为空") 106 | private String sex; 107 | 108 | 109 | public @interface Update { 110 | } 111 | } 112 | ``` 113 | 控制层代码,BindingResult bindingResult 必须写在方法的接收参数上,否则校验失败,校验逻辑统一走@FwValidate切面处理 114 | ```java 115 | /** 116 | * 添加用户 117 | * @Author xuyisu 118 | * @Date 2019/10/25 119 | * @Param [user] 120 | * @Return com.yisu.common.result.FwResult 121 | */ 122 | @PostMapping 123 | @ApiOperation(value = "创建用户") 124 | @FwValidate 125 | public FwResult createUser(@Valid @RequestBody User user,BindingResult bindingResult) { 126 | if(bindingResult.hasErrors()) 127 | { 128 | return FwResult.failed(); 129 | } 130 | FwResult userInfo=userService.createUser(user); 131 | return userInfo; 132 | } 133 | 134 | /** 135 | * 更新用户 136 | * @Author xuyisu 137 | * @Date 2019/10/25 138 | * @Param [user] 139 | * @Return com.yisu.common.result.FwResult 140 | */ 141 | @PutMapping("/updateUser") 142 | @ApiOperation(value = "更新用户") 143 | @FwValidate 144 | public FwResult updateUser(@Validated(User.Update.class) @RequestBody User user,BindingResult bindingResult) { 145 | if(bindingResult.hasErrors()) 146 | { 147 | return FwResult.failed(); 148 | } 149 | FwResult userInfo=userService.updateUser(user); 150 | return userInfo; 151 | } 152 | ``` 153 | ### 3.swagger 配置 154 | ```java 155 | /** 156 | * api页面 /swagger-ui.html 157 | * @author xuyisu 158 | * @date 2019-10-15 159 | */ 160 | 161 | @Configuration 162 | @EnableSwagger2 163 | public class SwaggerConfig { 164 | 165 | 166 | @Value("${swagger.enabled}") 167 | private Boolean enabled; 168 | 169 | @Bean 170 | public Docket createRestApi() { 171 | return new Docket(DocumentationType.SWAGGER_2) 172 | .enable(enabled) 173 | .apiInfo(apiInfo()) 174 | .select() 175 | .paths(Predicates.not(PathSelectors.regex("/error.*"))) 176 | .build(); 177 | } 178 | 179 | private ApiInfo apiInfo() { 180 | return new ApiInfoBuilder() 181 | .title("接口文档") 182 | .version("1.0") 183 | .build(); 184 | } 185 | 186 | } 187 | ``` 188 | 浏览器输入`http://localhost:8766/swagger-ui.html# ` 189 | ![swagger](images/swagger.png) 190 | 191 | ### 4.单元测试 192 | ```java 193 | /** 194 | * @ClassName UserControllerTest 195 | * @Author xuyisu 196 | * @Description 模拟http测试 197 | * @Date 2019/10/25 198 | */ 199 | @RunWith(SpringRunner.class) 200 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 201 | public class UserControllerTest { 202 | 203 | @Autowired 204 | private WebApplicationContext wac; 205 | 206 | private MockMvc mockMvc; 207 | 208 | @Before 209 | public void setup() { 210 | mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); 211 | } 212 | 213 | @Test 214 | public void whenGetUserInfoSuccess() throws Exception { 215 | String result = mockMvc.perform(get("/user/1") 216 | .contentType(MediaType.APPLICATION_JSON_UTF8)) 217 | .andExpect(status().isOk()) 218 | .andExpect(jsonPath("$.code").value(FwCommonConstants.SUCCESS)) 219 | .andReturn().getResponse().getContentAsString(); 220 | 221 | System.out.println(result); 222 | } 223 | //....... 224 | //具体请看代码`com.yisu.mock.UserControllerTest` 225 | 226 | ``` 227 | 228 | # 亲,点个star再走呗 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /images/swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuyisu/restful-api-demo/70223d265349b0c3586359d1f6227867dccff93b/images/swagger.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.yisu 8 | restful-api-demo 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 3.4 13 | Greenwich.SR2 14 | 2.9.2 15 | 4.6.7 16 | 2.1.10.RELEASE 17 | 2.7 18 | 2.6 19 | 3.2.2 20 | 1.9.4 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-parent 26 | 2.1.6.RELEASE 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-dependencies 34 | ${spring-cloud.version} 35 | pom 36 | import 37 | 38 | 39 | 40 | org.apache.commons 41 | commons-lang3 42 | ${commons-lang3.version} 43 | 44 | 45 | org.projectlombok 46 | lombok 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-web 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-test 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-starter-aop 59 | 60 | 61 | org.springframework.data 62 | spring-data-commons 63 | ${data-commons.version} 64 | 65 | 66 | 67 | commons-io 68 | commons-io 69 | ${commons-io.version} 70 | 71 | 72 | commons-lang 73 | commons-lang 74 | ${commons-lang.version} 75 | 76 | 77 | commons-collections 78 | commons-collections 79 | ${commons-collections.version} 80 | 81 | 82 | commons-beanutils 83 | commons-beanutils 84 | ${commons-beanutils.version} 85 | 86 | 87 | 88 | 89 | io.springfox 90 | springfox-swagger2 91 | ${swagger.version} 92 | 93 | 94 | io.springfox 95 | springfox-swagger-ui 96 | ${swagger.version} 97 | 98 | 99 | 100 | cn.hutool 101 | hutool-all 102 | ${hutool.version} 103 | 104 | 105 | 106 | 107 | 108 | 109 | org.springframework.boot 110 | spring-boot-maven-plugin 111 | 112 | 113 | 114 | org.apache.maven.plugins 115 | maven-compiler-plugin 116 | 2.3.2 117 | 118 | 1.8 119 | 1.8 120 | UTF-8 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | public 129 | aliyun nexus 130 | http://maven.aliyun.com/nexus/content/groups/public/ 131 | 132 | true 133 | 134 | 135 | 136 | 137 | 138 | public 139 | aliyun nexus 140 | http://maven.aliyun.com/nexus/content/groups/public/ 141 | 142 | true 143 | 144 | 145 | false 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/ApiApplication.java: -------------------------------------------------------------------------------- 1 | package com.yisu; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author xuyisu 8 | * @date 2018/9/29 9 | */ 10 | @SpringBootApplication 11 | public class ApiApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(ApiApplication.class); 15 | } 16 | 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/common/constant/FwCommonConstants.java: -------------------------------------------------------------------------------- 1 | package com.yisu.common.constant; 2 | 3 | /** 4 | * @ClassName FwCommonConstants 5 | * @Author xuyisu 6 | * @Description 公共常量 7 | * @Date 2019/10/11 8 | */ 9 | public class FwCommonConstants { 10 | //成功 11 | public static final int SUCCESS = 200; 12 | 13 | //失败 14 | public static final int FAIL = 500; 15 | 16 | /** 17 | * 默认开始页 18 | */ 19 | public static final int PAGE_NO=1; 20 | 21 | /** 22 | * 默认页大小 23 | */ 24 | public static final int PAGE_SIZE=20; 25 | /** 26 | * 默认用户账号 27 | */ 28 | public static final String USER_NAME = "admin"; 29 | /** 30 | * 树形节点的父节点 31 | * @Author xuyisu 32 | * @Date 2019/10/24 33 | * @Param 34 | * @Return 35 | */ 36 | public static final String PARENT_CODE = "0"; 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/common/exception/ControllerExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.yisu.common.exception; 2 | 3 | import com.yisu.common.result.FwResult; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.web.bind.MethodArgumentNotValidException; 6 | import org.springframework.web.bind.MissingServletRequestParameterException; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.ResponseBody; 10 | import org.springframework.web.bind.annotation.RestControllerAdvice; 11 | 12 | import javax.validation.ConstraintViolationException; 13 | import java.security.InvalidParameterException; 14 | 15 | /** 16 | * 验证异常处理 17 | * @Author xuyisu 18 | * @Date 2019/10/25 19 | * @Param 20 | * @Return 21 | */ 22 | @RestControllerAdvice 23 | public class ControllerExceptionHandler { 24 | 25 | @ExceptionHandler({InvalidParameterException.class, IllegalArgumentException.class, MissingServletRequestParameterException.class, MethodArgumentNotValidException.class, ConstraintViolationException.class}) 26 | public FwResult paramException(Exception e) { 27 | if (e instanceof MethodArgumentNotValidException) { 28 | return FwResult.failed(((MethodArgumentNotValidException) e).getBindingResult().getAllErrors().get(0).getDefaultMessage()); 29 | } 30 | 31 | if (e.getMessage() != null) { 32 | return FwResult.failed(e.getMessage()); 33 | } 34 | 35 | return FwResult.failed(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/common/exception/ValidateException.java: -------------------------------------------------------------------------------- 1 | package com.yisu.common.exception; 2 | 3 | import com.yisu.common.result.FwResult; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | /** 11 | * @ClassName ValidateException 12 | * @Author xuyisu 13 | * @Description 验证的异常捕捉 14 | * @Date 2019/10/25 15 | */ 16 | @Data 17 | @AllArgsConstructor 18 | public class ValidateException extends RuntimeException { 19 | 20 | private static final long serialVersionUID = 7207451175263593487L; 21 | 22 | private Set> errors; 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/common/result/FwResult.java: -------------------------------------------------------------------------------- 1 | package com.yisu.common.result; 2 | 3 | 4 | import com.yisu.common.constant.FwCommonConstants; 5 | import lombok.Data; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * @author xuyisu 11 | * @date 2019/9/20 12 | */ 13 | @Data 14 | public class FwResult implements Serializable { 15 | private static final long serialVersionUID = 1L; 16 | 17 | private int code; 18 | 19 | private String msg; 20 | 21 | private Object data; 22 | 23 | //分页信息 24 | private Object meta; 25 | 26 | public static FwResult ok() { 27 | return restResult(null, FwCommonConstants.SUCCESS, null, null); 28 | } 29 | 30 | public static FwResult ok(Object data) { 31 | return restResult(data, FwCommonConstants.SUCCESS, null, null); 32 | } 33 | 34 | public static FwResult ok(Object data, String msg) { 35 | return restResult(data, FwCommonConstants.SUCCESS, msg, null); 36 | } 37 | 38 | public static FwResult ok(Object data, String msg, Object meta) { 39 | return restResult(data, FwCommonConstants.SUCCESS, msg, meta); 40 | } 41 | 42 | public static FwResult failed() { 43 | return restResult(null, FwCommonConstants.FAIL, null, null); 44 | } 45 | 46 | public static FwResult failed(String msg) { 47 | return restResult(null, FwCommonConstants.FAIL, msg, null); 48 | } 49 | 50 | public static FwResult failed(Object data) { 51 | return restResult(data, FwCommonConstants.FAIL, null, null); 52 | } 53 | 54 | public static FwResult failed(Object data, String msg) { 55 | return restResult(data, FwCommonConstants.FAIL, msg, null); 56 | } 57 | 58 | private static FwResult restResult(Object data, int code, String msg, Object meta) { 59 | FwResult fwResult = new FwResult(); 60 | fwResult.setCode(code); 61 | fwResult.setData(data); 62 | fwResult.setMsg(msg); 63 | fwResult.setMeta(meta); 64 | return fwResult; 65 | } 66 | 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/common/validate/aop/FwValidate.java: -------------------------------------------------------------------------------- 1 | package com.yisu.common.validate.aop; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @ClassName FwValidate 10 | * @Author xuyisu 11 | * @Description 参数验证 12 | * @Date 2019/10/25 13 | */ 14 | @Target({ElementType.METHOD, ElementType.FIELD}) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface FwValidate { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/common/validate/aspect/FwValidateAsprct.java: -------------------------------------------------------------------------------- 1 | package com.yisu.common.validate.aspect; 2 | 3 | import com.yisu.common.exception.ValidateException; 4 | import com.yisu.common.result.FwResult; 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.validation.BindingResult; 11 | import org.springframework.validation.FieldError; 12 | import org.springframework.validation.ObjectError; 13 | 14 | import java.util.*; 15 | 16 | /** 17 | * @ClassName FwValidateAsprct 18 | * @Author xuyisu 19 | * @Description 验证信息切面 20 | * @Date 2019/10/25 21 | */ 22 | @Aspect 23 | @Component 24 | public class FwValidateAsprct { 25 | /** 26 | * 配置切入点 27 | */ 28 | @Pointcut("@annotation(com.yisu.common.validate.aop.FwValidate)") 29 | public void validatePointcut() {} 30 | 31 | @Around("validatePointcut()") 32 | public Object logAround(ProceedingJoinPoint pjp) throws Throwable { 33 | Object[] args = pjp.getArgs(); 34 | for (Object arg : args) { 35 | if(arg instanceof BindingResult) { 36 | BindingResult errors = (BindingResult)arg; 37 | if (errors.hasErrors()) { 38 | throw new ValidateException(fail(errors)); 39 | } 40 | } 41 | } 42 | Object result = pjp.proceed(); 43 | return result; 44 | } 45 | 46 | 47 | private Set> fail(BindingResult errors){ 48 | Set> res=new HashSet<>(); 49 | List fieldErrors = errors.getFieldErrors(); 50 | fieldErrors.stream().forEach((FieldError fieldError)->{ 51 | Map map = new HashMap<>(); 52 | map.put(fieldError.getField(),fieldError.getDefaultMessage()); 53 | res.add(map); 54 | }); 55 | return res; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/config/swagger2/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.yisu.config.swagger2; 2 | 3 | import com.google.common.base.Predicates; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import springfox.documentation.builders.ApiInfoBuilder; 8 | import springfox.documentation.builders.PathSelectors; 9 | import springfox.documentation.service.ApiInfo; 10 | import springfox.documentation.spi.DocumentationType; 11 | import springfox.documentation.spring.web.plugins.Docket; 12 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 13 | 14 | /** 15 | * api页面 /swagger-ui.html 16 | * @author xuyisu 17 | * @date 2019-10-15 18 | */ 19 | 20 | @Configuration 21 | @EnableSwagger2 22 | public class SwaggerConfig { 23 | 24 | 25 | @Value("${swagger.enabled}") 26 | private Boolean enabled; 27 | 28 | @Bean 29 | public Docket createRestApi() { 30 | return new Docket(DocumentationType.SWAGGER_2) 31 | .enable(enabled) 32 | .apiInfo(apiInfo()) 33 | .select() 34 | .paths(Predicates.not(PathSelectors.regex("/error.*"))) 35 | .build(); 36 | } 37 | 38 | private ApiInfo apiInfo() { 39 | return new ApiInfoBuilder() 40 | .title("接口文档") 41 | .version("1.0") 42 | .build(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/restful/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.yisu.restful.controller; 2 | 3 | import cn.hutool.json.JSONUtil; 4 | import com.yisu.common.result.FwResult; 5 | import com.yisu.common.validate.aop.FwValidate; 6 | import com.yisu.restful.data.DataMock; 7 | import com.yisu.restful.entity.User; 8 | import com.yisu.restful.service.UserService; 9 | import io.swagger.annotations.ApiOperation; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.data.web.PageableDefault; 12 | import org.springframework.stereotype.Controller; 13 | import org.springframework.validation.BindingResult; 14 | import org.springframework.validation.annotation.Validated; 15 | import org.springframework.web.bind.annotation.*; 16 | import org.springframework.data.domain.Pageable; 17 | 18 | /** 19 | * @ClassName UserController 20 | * @Author xuyisu 21 | * @Description 用户控制层 22 | * @Date 2019/10/25 23 | */ 24 | @Controller 25 | @RestController 26 | @RequestMapping("user") 27 | public class UserController { 28 | 29 | @Autowired 30 | private UserService userService; 31 | 32 | /** 33 | * 根据id查询用户 表达式 \\d+主要是为了限制id为整数 34 | * @Author xuyisu 35 | * @Date 2019/10/25 36 | * @Param [id] 37 | * @Return com.yisu.common.result.FwResult 38 | */ 39 | @ApiOperation(value = "根据id查询用户") 40 | @GetMapping("/{id:\\d+}") 41 | public FwResult getUser(@PathVariable Long id) 42 | { 43 | FwResult userInfo = userService.getUserById(id); 44 | return userInfo; 45 | } 46 | /** 47 | * 根据id删除用户 48 | * @Author xuyisu 49 | * @Date 2019/10/25 50 | * @Param [id] 51 | * @Return com.yisu.common.result.FwResult 52 | */ 53 | @ApiOperation(value = "根据id删除用户") 54 | @DeleteMapping("/{id:\\d+}") 55 | public FwResult deleteUser(@PathVariable Long id) 56 | { 57 | FwResult userInfo = userService.deleteUserById(id); 58 | return userInfo; 59 | } 60 | /** 61 | * 添加用户 62 | * @Author xuyisu 63 | * @Date 2019/10/25 64 | * @Param [user] 65 | * @Return com.yisu.common.result.FwResult 66 | */ 67 | @PostMapping 68 | @ApiOperation(value = "创建用户") 69 | @FwValidate 70 | public FwResult createUser(@Validated @RequestBody User user,BindingResult bindingResult) { 71 | if(bindingResult.hasErrors()) 72 | { 73 | return FwResult.failed(); 74 | } 75 | FwResult userInfo=userService.createUser(user); 76 | return userInfo; 77 | } 78 | 79 | /** 80 | * 更新用户 81 | * @Author xuyisu 82 | * @Date 2019/10/25 83 | * @Param [user] 84 | * @Return com.yisu.common.result.FwResult 85 | */ 86 | @PutMapping("/updateUser") 87 | @ApiOperation(value = "更新用户") 88 | @FwValidate 89 | public FwResult updateUser(@Validated(User.Update.class) @RequestBody User user,BindingResult bindingResult) { 90 | if(bindingResult.hasErrors()) 91 | { 92 | return FwResult.failed(); 93 | } 94 | FwResult userInfo=userService.updateUser(user); 95 | return userInfo; 96 | } 97 | 98 | @PostMapping("/page") 99 | @ApiOperation(value = "用户查询服务") 100 | public FwResult query(@RequestBody User user, 101 | @PageableDefault(page = 2, size = 17) Pageable pageable) { 102 | System.out.println(JSONUtil.toJsonStr(user)); 103 | System.out.println(pageable.getPageSize()); 104 | System.out.println(pageable.getPageNumber()); 105 | System.out.println(pageable.getSort()); 106 | 107 | 108 | return FwResult.ok(DataMock.getUserAll()); 109 | } 110 | 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/restful/data/DataMock.java: -------------------------------------------------------------------------------- 1 | package com.yisu.restful.data; 2 | 3 | import com.yisu.restful.entity.User; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @ClassName DataMock 10 | * @Author xuyisu 11 | * @Description 模拟数据 12 | * @Date 2019/10/25 13 | */ 14 | public class DataMock { 15 | 16 | public static List getUserAll(){ 17 | List list =new ArrayList<>(); 18 | User user1=new User(1L,"张三","123456","男"); 19 | list.add(user1); 20 | User user2=new User(2L,"李四","123456","男"); 21 | list.add(user2); 22 | User user3=new User(3L,"王五","123456","女"); 23 | list.add(user3); 24 | return list; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/restful/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.yisu.restful.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import javax.validation.GroupSequence; 8 | import javax.validation.constraints.NotNull; 9 | import java.io.Serializable; 10 | 11 | /** 12 | * @ClassName User 13 | * @Author xuyisu 14 | * @Description 用户信息 15 | * @Date 2019/10/25 16 | */ 17 | @Data 18 | @AllArgsConstructor 19 | @NoArgsConstructor 20 | public class User implements Serializable { 21 | private static final long serialVersionUID = 1838417777538323571L; 22 | 23 | //主键 24 | @NotNull(message = "主键不能为空",groups =Update.class) 25 | private Long id; 26 | //用户名 27 | @NotNull(message = "用户名不能为空") 28 | private String userName; 29 | //密码 30 | @NotNull(message = "密码不能为空") 31 | private String password; 32 | //性别 33 | @NotNull(message = "性别不能为空") 34 | private String sex; 35 | 36 | 37 | 38 | public @interface Update { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/restful/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.yisu.restful.service; 2 | 3 | import com.yisu.common.result.FwResult; 4 | import com.yisu.restful.entity.User; 5 | 6 | /** 7 | * @ClassName service 8 | * @Author xuyisu 9 | * @Description 接口信息 10 | * @Date 2019/10/25 11 | */ 12 | public interface UserService { 13 | /** 14 | * 根据id查询用户信息 15 | * @Author xuyisu 16 | * @Date 2019/10/25 17 | * @Param [id] 18 | * @Return com.yisu.common.result.FwResult 19 | */ 20 | FwResult getUserById(Long id); 21 | /** 22 | * 23 | * @Author xuyisu 24 | * @Date 2019/10/25 25 | * @Param [id] 26 | * @Return com.yisu.common.result.FwResult 27 | */ 28 | FwResult deleteUserById(Long id); 29 | /** 30 | * 创建用户 31 | * @Author xuyisu 32 | * @Date 2019/10/25 33 | * @Param [user] 34 | * @Return com.yisu.common.result.FwResult 35 | */ 36 | FwResult createUser(User user); 37 | /** 38 | * 跟新用户 39 | * @Author xuyisu 40 | * @Date 2019/10/28 41 | * @Param [user] 42 | * @Return com.yisu.common.result.FwResult 43 | */ 44 | FwResult updateUser(User user); 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/yisu/restful/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.yisu.restful.service.impl; 2 | 3 | import com.yisu.common.result.FwResult; 4 | import com.yisu.restful.data.DataMock; 5 | import com.yisu.restful.entity.User; 6 | import com.yisu.restful.service.UserService; 7 | import org.apache.commons.lang3.RandomUtils; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | /** 14 | * @ClassName UserServiceImpl 15 | * @Author xuyisu 16 | * @Description 接口实现 17 | * @Date 2019/10/25 18 | */ 19 | @Service 20 | public class UserServiceImpl implements UserService { 21 | 22 | @Override 23 | public FwResult getUserById(Long id) { 24 | List collect = DataMock.getUserAll().stream().filter(user -> user.getId() == id).collect(Collectors.toList()); 25 | return FwResult.ok(collect.get(0)); 26 | } 27 | 28 | @Override 29 | public FwResult deleteUserById(Long id) { 30 | boolean b = DataMock.getUserAll().removeIf(user -> user.getId() == id); 31 | if(!b) 32 | return FwResult.failed("可能没有对应的用户信息"); 33 | return FwResult.ok("删除成功"); 34 | } 35 | 36 | @Override 37 | public FwResult createUser(User user) { 38 | user.setId(RandomUtils.nextLong(4,100000)); 39 | DataMock.getUserAll().add(user); 40 | return FwResult.ok(user); 41 | } 42 | 43 | @Override 44 | public FwResult updateUser(User user) { 45 | List userAll = DataMock.getUserAll(); 46 | for (User use:userAll) { 47 | if(use.getId()==user.getId()) 48 | { 49 | use.setUserName(user.getUserName()); 50 | use.setSex(user.getSex()); 51 | use.setPassword(user.getPassword()); 52 | return FwResult.ok("更新成功"); 53 | } 54 | } 55 | return FwResult.failed("更新失败"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8766 3 | spring: 4 | application: 5 | name: restful-api-demo 6 | swagger: 7 | enabled: true #swagger 开关 8 | logging: 9 | level: 10 | com.yisu: debug -------------------------------------------------------------------------------- /src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | febs 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ${log.colorPattern} 13 | 14 | 15 | 16 | 17 | 18 | 19 | ${log.path}/info/info.%d{yyyy-MM-dd}.log 20 | ${log.maxHistory} 21 | 22 | 23 | ${log.pattern} 24 | 25 | 26 | INFO 27 | ACCEPT 28 | DENY 29 | 30 | 31 | 32 | 33 | 34 | ${log.path}/error/error.%d{yyyy-MM-dd}.log 35 | 36 | 37 | ${log.pattern} 38 | 39 | 40 | ERROR 41 | ACCEPT 42 | DENY 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/test/java/com/yisu/mock/UserControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.yisu.mock; 2 | 3 | import com.yisu.common.constant.FwCommonConstants; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.test.context.junit4.SpringRunner; 11 | import org.springframework.test.web.servlet.MockMvc; 12 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 13 | import org.springframework.web.context.WebApplicationContext; 14 | 15 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 16 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 17 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 18 | 19 | /** 20 | * @ClassName UserControllerTest 21 | * @Author xuyisu 22 | * @Description 模拟http测试 23 | * @Date 2019/10/25 24 | */ 25 | @RunWith(SpringRunner.class) 26 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 27 | public class UserControllerTest { 28 | 29 | @Autowired 30 | private WebApplicationContext wac; 31 | 32 | private MockMvc mockMvc; 33 | 34 | @Before 35 | public void setup() { 36 | mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); 37 | } 38 | 39 | @Test 40 | public void whenGetUserInfoSuccess() throws Exception { 41 | String result = mockMvc.perform(get("/user/1") 42 | .contentType(MediaType.APPLICATION_JSON_UTF8)) 43 | .andExpect(status().isOk()) 44 | .andExpect(jsonPath("$.code").value(FwCommonConstants.SUCCESS)) 45 | .andReturn().getResponse().getContentAsString(); 46 | 47 | System.out.println(result); 48 | } 49 | 50 | @Test 51 | public void whenGetUserInfoFail() throws Exception { 52 | String result = mockMvc.perform(get("/user/name") 53 | .contentType(MediaType.APPLICATION_JSON_UTF8)) 54 | .andExpect(status().is4xxClientError()) 55 | .andReturn().getResponse().getContentAsString(); 56 | 57 | System.out.println(result); 58 | } 59 | 60 | @Test 61 | public void whenDeleteUserInfoSuccess() throws Exception { 62 | String result = mockMvc.perform(delete("/user/1") 63 | .contentType(MediaType.APPLICATION_JSON_UTF8)) 64 | .andExpect(status().isOk()) 65 | .andExpect(jsonPath("$.code").value(FwCommonConstants.SUCCESS)) 66 | .andReturn().getResponse().getContentAsString(); 67 | 68 | System.out.println(result); 69 | } 70 | 71 | @Test 72 | public void whenDeleteUserInfoFail() throws Exception { 73 | String result = mockMvc.perform(delete("/user/6") 74 | .contentType(MediaType.APPLICATION_JSON_UTF8)) 75 | .andExpect(status().isOk()) 76 | .andExpect(jsonPath("$.code").value(FwCommonConstants.FAIL)) 77 | .andReturn().getResponse().getContentAsString(); 78 | 79 | System.out.println(result); 80 | } 81 | 82 | 83 | @Test 84 | public void whenAddUserInfoSuccess() throws Exception { 85 | String content = "{\"userName\":\"tom\",\"password\":\"123456\",\"sex\":\"男\"}"; 86 | String result = mockMvc.perform(post("/user") 87 | .contentType(MediaType.APPLICATION_JSON_UTF8) 88 | .content(content)) 89 | .andExpect(status().isOk()) 90 | .andExpect(jsonPath("$.code").value(FwCommonConstants.SUCCESS)) 91 | .andReturn().getResponse().getContentAsString(); 92 | 93 | System.out.println(result); 94 | } 95 | 96 | @Test 97 | public void whenAddUserInfoFail() throws Exception { 98 | String content = "{\"userName\":\"tom\",\"password\":null,\"sex\":\"男\"}"; 99 | String result = mockMvc.perform(post("/user") 100 | .contentType(MediaType.APPLICATION_JSON_UTF8) 101 | .content(content)) 102 | .andExpect(status().isOk()) 103 | .andExpect(jsonPath("$.code").value(FwCommonConstants.FAIL)) 104 | .andReturn().getResponse().getContentAsString(); 105 | 106 | System.out.println(result); 107 | } 108 | 109 | @Test 110 | public void whenUpdateUserInfoSuccess() throws Exception { 111 | String content = "{\"userName\":\"tom\",\"password\":\"123456\",\"sex\":\"男\",\"id\":\"1\"}"; 112 | String result = mockMvc.perform(put("/user/1") 113 | .contentType(MediaType.APPLICATION_JSON_UTF8) 114 | .content(content)) 115 | .andExpect(status().isOk()) 116 | .andExpect(jsonPath("$.code").value(FwCommonConstants.SUCCESS)) 117 | .andReturn().getResponse().getContentAsString(); 118 | 119 | System.out.println(result); 120 | } 121 | 122 | @Test 123 | public void whenUpdateUserInfoFail() throws Exception { 124 | String content = "{\"userName\":\"tom\",\"password\":\"123456\",\"sex\":\"男\"}"; 125 | String result = mockMvc.perform(put("/user/1") 126 | .contentType(MediaType.APPLICATION_JSON_UTF8) 127 | .content(content)) 128 | .andExpect(status().isOk()) 129 | .andExpect(jsonPath("$.code").value(FwCommonConstants.FAIL)) 130 | .andReturn().getResponse().getContentAsString(); 131 | 132 | System.out.println(result); 133 | } 134 | 135 | 136 | @Test 137 | public void whenQuerySuccess() throws Exception { 138 | String content = "{\"userName\":\"tom\",\"password\":\"123456\",\"sex\":\"男\",\"id\":\"1\"}"; 139 | String result = mockMvc.perform( 140 | post("/user/page").param("size", "15") 141 | .param("page", "3") 142 | .contentType(MediaType.APPLICATION_JSON_UTF8).content(content)) 143 | .andExpect(status().isOk()).andExpect(jsonPath("$.code").value(FwCommonConstants.SUCCESS)) 144 | .andReturn().getResponse().getContentAsString(); 145 | 146 | System.out.println(result); 147 | } 148 | 149 | @Test 150 | public void whenQueryFail() throws Exception { 151 | String content = "{\"userName\":\"tom\",\"password\":\"123456\",\"sex\":\"男\"}"; 152 | String result = mockMvc.perform( 153 | post("/user/page").param("size", "15") 154 | .param("page", "3") 155 | .contentType(MediaType.APPLICATION_JSON_UTF8).content(content)) 156 | .andExpect(status().isOk())//.andExpect(jsonPath("$.code").value(FwCommonConstants.FAIL)) 157 | .andReturn().getResponse().getContentAsString(); 158 | 159 | System.out.println(result); 160 | } 161 | } 162 | --------------------------------------------------------------------------------