SpringMvc
概述


实例
MvcConfig.java
package springmvc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration
@ComponentScan("springmvc.controller")
public class MvcConfig {
@Bean
public RequestMappingHandlerMapping handlerMapping() {
return new RequestMappingHandlerMapping();
}
@Bean
public RequestMappingHandlerAdapter handlerAdapter() {
return new RequestMappingHandlerAdapter();
}
}
SpringMvcInit.java
package springmvc.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpringMvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
HelloController.java
package springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class HelloController {
@RequestMapping("springmvc/hello")
@ResponseBody
public String hello() {
System.out.println("hello springmvc");
return "hello";
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.it</groupId>
<artifactId>ssm-spring-mvc</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>spring-mvc01</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/jakarta.platform/jakarta.jakartaee-web-api -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>9.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.1</version>
</dependency>
</dependencies>
</project>
请求参数获取方式
通过方法参数直接接收
@RequestMapping("/test1")
public String test1(String name){
System.out.println(name);
return "test";
}
使用 @RequestParam 注解来获取请求参数
// 使用@RequestParam注解,其中value表示指定接收的参数名称;required表示是否可以为空,默认true;defaultValue表示为空时的默认值
@RequestMapping("/test2")
public String test2(@RequestParam(value = "name",required = false,defaultValue = "张三") String name){
System.out.println(name);
return "test";
}
使用@PathVariable注解获取参数
// 使用@PathVariable注解,传输参数时可以不通过url?aa=aa&bb=bb的方式,而是通过url/aa/bb的方式进行参数传输
@RequestMapping("/test3/{name}")
public String test3(@PathVariable String name){
System.out.println(name);
return "test";
}
使用一个pojo对象封装请求参数
// 当请求是以表单参数或URL参数的方式传递数据,而不是将数据包含在请求体中的JSON或XML格式,
// SpringMVC会根据参数名称和请求参数名称的匹配自动将请求参数映射到对象的属性上。
@RequestMapping("/test4")
public String test4(Student student){
System.out.println(student);
return "test";
}
使用 @RequestHeader 注解来获取请求头中的信息
// 使用@RequestHeader,可以将请求中的指定头部信息
@RequestMapping("/test6")
public String test6(@RequestHeader("User-Agent") String userAgent){
System.out.println(userAgent);
return "test";
}
使用 @CookieValue 注解来获取请求中的 Cookie 值
// 使用@CookieValue获取cookie中的值
@RequestMapping("/test7")
public String test7(@CookieValue("name") String name) {
System.out.println(name);
// 使用 username 处理业务逻辑
return "test";
}
直接在方法参数中声明 HttpServletRequest 对象来获取完整的请求信息
// 直接在方法参数中声明HttpServletRequest,再通过request获取其中的其他值
@RequestMapping("/test8")
public String test8(HttpServletRequest request) {
System.out.println(request.getParameter("name"));
// 使用 username 处理业务逻辑
return "test";
}
响应
返回视图名称字符串
// 返回视图名称字符串
@RequestMapping("/res1")
public String res1(){
// 因为视图解析器进行类配置,所以最终会走/template/test.jsp这个页面
return "test";
}
返回视图对象(View Object)
// 返回视图对象
// 跳过视图解析器的过程,这在需要更精确的控制视图的情况下很有用。
@RequestMapping("/res2")
public View res2(){
return new InternalResourceView("/template/test.jsp"); // 返回视图对象
}
返回ModelAndView对象
// 返回ModelAndView对象
// 返回一个ModelAndView对象,除了View的视图以外还可以添加数据
@RequestMapping("/res3")
public ModelAndView res3(){
// 创建一个ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
// 添加一个值,类似于Map的添加方式,在前端可以通过el表达式进行获取
modelAndView.addObject("name","小米");
// 设置跳转的视图名称,这将走视图解析器,因此类似于第一种只需要视图的名称就行
modelAndView.setViewName("test");
return modelAndView;
}
重定向
// 重定向,可以跳过视图解析器
@RequestMapping("/res4")
public String res4(){
return "redirect:/template/test.jsp";
}
请求转发
// 请求转发,可以跳过视图解析器
@RequestMapping("/res5")
public String res5(){
return "forward:/template/test.jsp";
}
无返回值
// 无返回值
// 在没有返回值时,需要加上@ResponseBody,否则会默认将请求路径当做视图,最终会返回一个页面/template/res6.jsp
@ResponseBody
@RequestMapping("/res6")
public void res6(){
System.out.println("你好");
}
返回一个任意的对象
// 返回一个任意的对象
// 返回一个对象时,需要加上@ResponseBody注解,否则同上
// 当返回类型为String类型时,如果有一个@ResponseBody注解,那么只是单纯将字符串进行了返回,是一个text/html的格式
// 当返回类型为其他对象时,一般是以JSON格式进行返回,需要加上jackson-databind依赖
// 如果上述两种返回类型出现中文乱码的情况,需要配置消息转换器,去处理返回类型的编码格式
@ResponseBody
@RequestMapping("/res7")
public List<Map<String,String>> res7(){
HashMap<String, String> map = new HashMap<>();
map.put("id","1");
map.put("name","张三");
map.put("age","15");
HashMap<String, String> map1 = new HashMap<>();
map1.put("id","2");
map1.put("name","王五");
map1.put("age","18");
ArrayList<Map<String, String>> maps = new ArrayList<>();
maps.add(map);
maps.add(map1);
return maps;
}
返回响应状态码和消息
// 返回响应状态码和消息
// @ResponseStatus中可以设置当前请求最终响应回去的状态码以及其对应的消息
@ResponseBody
@ResponseStatus(HttpStatus.NOT_EXTENDED)
@RequestMapping("/res8")
public String res8(){
return "这是一个测试方法";
}
实例
MvcConfig.java
package config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@ComponentScan("json")
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/jsp/", ".jsp");
}
}
SpringMVInit.java
package config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpringMVInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
JsonController.java
package json;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import pojo.User;
@Controller
@RequestMapping("json")
public class JsonController {
@GetMapping("data")
@ResponseBody
public User data(){
User user = new User();
user.setName("Tom");
user.setAge(20);
return user;
}
}
User.java
package pojo;
import lombok.Data;
@Data
public class User {
private String name;
private int age;
}
SpringMVC注解详解
- @Controller: 标记一个类为控制器,处理用户请求并返回视图或数据。用于标识处理请求的控制器类。
- @RequestMapping: 映射请求 URL 到处理方法,用于指定请求路径和 HTTP 方法。用于将请求映射到具体的处理方法,可以用于类级别和方法级别。
- @GetMapping、@PostMapping、@PutMapping、@DeleteMapping: 分别映射 GET、POST、PUT、DELETE 请求。用于更明确地指定请求方法。
- @RequestParam: 从请求参数中获取值,可设置默认值和是否必需。获取请求参数,用于处理方法参数。
- @PathVariable: 从 URL 路径中获取值,用于动态路径参数。从 URL 中提取参数值,用于处理方法参数。
- @RequestBody: 将请求体中的数据反序列化为对象,用于处理 JSON 或 XML 数据。将请求体数据映射到方法参数。
- @ResponseBody: 将方法返回值序列化为响应体,常用于返回 JSON 或 XML 数据。将方法返回值直接作为响应体返回给客户端。
- @ModelAttribute: 用于绑定请求参数到模型对象。将请求参数绑定到模型对象,通常用于表单数据绑定。
- @Valid: 用于数据校验,配合 JSR-303 校验注解使用。用于在处理方法中进行数据校验。
- @InitBinder: 用于初始化数据绑定,自定义数据转换和验证规则。自定义数据绑定和验证规则。
- @SessionAttributes: 用于将模型属性暂存到会话中,多用于表单数据的临时存储。将模型属性存储在会话中,以供多个请求使用。
- @ModelAttribute: 在方法参数上使用,表示将会话中的属性绑定到方法参数上。在方法参数中获取会话中的属性。
- @ExceptionHandler: 用于处理控制器中的异常,定义全局或局部的异常处理方法。处理控制器中的异常情况。
- @RequestMapping、@GetMapping 等的 "produces" 和 "consumes" 属性: 用于指定请求的媒体类型(Content-Type)和响应的媒体类型(Accept)。更精确地控制请求和响应的媒体类型。
- @RequestMapping 的 "params" 和 "headers" 属性: 用于基于请求参数和头部信息进行请求映射。基于请求参数和头部信息进行请求映射。
Restful
POST(添加)、DELETE(删除)、PUT(修改)、GET(查询)
# 1.使用名词而不是动词
- 不要使用:
如:
/getAllUsers get /users get /users/002
/createNewUser post /users
/deleteAllUser delete /users/001
# 2.Get方法和查询参数不应该涉及状态改变
- 使用PUT, POST 和DELETE 方法 而不是 GET 方法来改变状态,不要使用GET 进行状态改变
# 3.使用复数名词
- 不要混淆名词单数和复数,为了保持简单,只对所有资源使用复数。
如:
/cars 而不是 /car
/users 而不是 /user
/products 而不是 /product
/settings 而不是 /setting
/orders 而不是 /order
# 4. 使用子资源表达关系
- 如果一个资源与另外一个资源有关系,使用子资源:
如:
GET /cars/711/drivers/ 返回 car 711的所有司机
GET /cars/711/drivers/4 返回 car 711的4号司机
GET /users/11/pets 返回 user 11的所有宠物
GET /users/11/pets/2 返回 user 11的2号宠物
# 5.使用Http头声明序列化格式
- 在客户端和服务端,双方都要知道通讯的格式,格式在HTTP-Header中指定
对于controller:
Accept 定义接受的类型
Content-Type 定义响应类型
# 6.为集合提供过滤 排序 选择和分页等功能
- Filtering过滤:使用唯一的查询参数进行
GET /cars?color=red 返回红色的cars
GET /cars?seats<=2 返回小于两座位的cars集合
- Sorting排序:允许针对多个字段排序
GET /cars?sort=-manufactorer,+model
这是返回根据生产者降序和模型升序排列的car集合
- Field selection
移动端能够显示其中一些字段,它们其实不需要一个资源的所有字段,给API消费者一个选择字段的能力,这会降低网络流量,提高API可用性。
GET /cars?fields=manufacturer,model,id,color
- Paging分页
使用 limit 和offset.实现分页,缺省limit=20 和offset=0;
GET /cars?offset=10&limit=5
为了将总数发给客户端,使用订制的HTTP头: X-Total-Count.
链接到下一页或上一页可以在HTTP头的link规定,遵循Link规定:
Link: <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=15&limit=5>; rel="next",<https://blog.mwaysolutions.com/sample/api/v1/cars?offset=50&limit=3>; rel="last",<https://blog.mwaysolutions.com/sample/api/v1/cars?offset=0&limit=5>; rel="first",<https://blog.mwaysolutions.com/sample/api/v1/cars?offset=5&limit=5>; rel="prev",
# 7.版本化你的API 支付宝 v1 v2 v3
- 使得API版本变得强制性,不要发布无版本的API,使用简单数字,避免小数点如2.5.
一般在Url后面使用?v
/blog/api/v1
# 8. 使用Http状态码处理错误
- 如果你的API没有错误处理是很难的,只是返回500和出错堆栈不一定有用
- Http状态码提供70个出错,我们只要使用10个左右:
`200 – OK – 一切正常
`201 – OK – 新的资源已经成功创建
`204 – OK – 资源已经成功删除
`304 – Not Modified – 客户端使用缓存数据
`400 – Bad Request – 请求无效,需要附加细节解释如 "JSON无效"
`401 – Unauthorized – 请求需要用户验证
`403 – Forbidden – 服务器已经理解了请求,但是拒绝服务或这种请求的访问是不允许的。
`404 – Not found – 没有发现该资源
`422 – Unprocessable Entity – 只有服务器不能处理实体时使用,比如图像不能被格式化,或者重要字段丢失。
`500 – Internal Server Error – API开发者应该避免这种错误。
使用详细的错误包装错误: 状态码 错误信息 正确:状态码 + 数据 复杂的话还有header头信息
{
"errors": [
{
"userMessage": "Sorry, the requested resource does not exist", // 错误信息
"internalMessage": "No car found in the database",
"code": 34, // 状态码
"more info": "http://dev.mwaysolutions.com/blog/api/v1/errors/12345" // 错误链接
}
]
}

package controller;
import org.springframework.web.bind.annotation.*;
import pojo.User;
import java.util.List;
@RestController
@RequestMapping("user")
public class UserController {
@GetMapping
public List<User> page(@RequestParam(required = false,defaultValue = "1")int page,
@RequestParam(required = false,defaultValue = "10")int size){
System.out.println(page+" "+size);
return null;
}
@PostMapping
public User save(@RequestBody User user){
return user;
}
@GetMapping("id")
public User detail(@PathVariable Integer id){
return null;
}
@PutMapping
public User update(@RequestBody User user){
return user;
}
@DeleteMapping("id")
public User delete(@PathVariable Integer id){
return null;
}
@GetMapping("search")
public List<User> search(String keyword,
@RequestParam(required = false,defaultValue = "1") int page,
@RequestParam(required = false,defaultValue = "10") int size){
return null;
}
}
全局异常处理
package com.zking.ssm.book.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import java.util.HashMap;
import java.util.Map;
/**
* SpingMVC提供的第三种种全局异常处理方式
* 1)@ControllerAdvice +@ExceptionHandler
* 2)@RestControllerAdvice +@ExceptionHandler
* @RestControllerAdvice ==@Controller +@ResponseBody 返回JSON的数据格式,绕开视图解析器
*/
@ControllerAdvice
public class GlobalException2{
@ExceptionHandler
public ModelAndView exceptionHandler(Exception e){
ModelAndView mv=new ModelAndView();
//设置错误页面
mv.setViewName("error");
//判断异常类型
if(e instanceof BusinessException){
BusinessException ex=(BusinessException)e;
mv.addObject("msg","系统繁忙,请稍后再试.......");
}
mv.setView(new MappingJackson2JsonView());
return mv;
}
}
package com.zking.ssm.book.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
import java.util.HashMap;
import java.util.Map;
/**
* SpingMVC提供的第三种种全局异常处理方式
* 1)@ControllerAdvice +@ExceptionHandler
* 2)@RestControllerAdvice +@ExceptionHandler
* @RestControllerAdvice ==@Controller +@ResponseBody 返回JSON的数据格式,绕开视图解析器
*/
@RestControllerAdvice
public class GlobalException2{
@ExceptionHandler
public Map<String, Object> exceptionHandler(Exception e){
Map<String, Object> json=new HashMap();
//判断异常类型
if(e instanceof BusinessException){
json.put("msg","系统繁忙,请稍后再试.......");
json.put("code",500);
}
return json;
}
}
拦截器
拦截器接口
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
实例
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("请求来了");
// ture表示放行
return true;
}
}
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
// 重写添加拦截器的方法,来注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册拦截器
registry.addInterceptor(new LogInterceptor());
// 可传入拦截器配置信息
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/login");
}
}
Validation参数校验注解
| 注解 | 描述 |
|---|---|
| @AssertFalse | 被注解的元素必须为false |
| @AssertTrue | 被注解的元素必须为True |
| @DecimalMax(value) | 被注解的元素必须为一个数字,其值必须小于等于指定的最小值 |
| @DecimalMin(Value) | 被注解的元素必须为一个数字,其值必须大于等于指定的最小值 |
| @Digits(integer=, fraction=) | 被注解的元素必须为一个数字,其值必须在可接受的范围内 |
| 被注释的元素必须是电子邮箱 | |
| @Future | 被注解的元素必须是日期,必须是将来日期 |
| @FutureOrPresent | |
| @Past | 被注解的元素必须是日期,必须是过去日期 |
| @PastOrPresent | |
| @Max(value) | 被注解的元素必须为一个数字,其值必须小于等于指定的最大值 |
| @Min(value) | 被注解的元素必须为一个数字,其值必须大于等于指定的最小值 |
| @Negative | |
| @NegativeOrZero | |
| @Null | 被注解的元素必须为null |
| @NotNull | 被注解的元素必须不为null |
| @NotBlank | CharSequence子类型,验证注解的元素值不为空(包括不为null或去除首位空格后长度为0) |
| @NotEmpty | 被注释的对象必须不为空(数据:String,Collection,Map,arrays) |
| @Size(min=, max=) | 被注解的元素必须在制定的范围(数据类型:String, Collection, Map and arrays) |
| @Pattern(regex=, flag=) | 被注解的元素必须符合正则表达式 |
| @Positive | |
| @PositiveOrZero | |
| @Valid | 递归的对关联对象进行校验, 如果关联对象是个集合或者数组, 那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验 |
| 注解 | 描述 |
|---|---|
| @Length(min=, max=) | 被注释的字符串的大小必须在指定的范围内 |
| @Range(min=, max=) | 被注释的元素必须在合适的范围内 (支持BigDecimal, BigInteger, String, byte, short, int, long和原始类型的包装类 ) |
| @URL(protocol=, host=, port=, regexp=, flags=) | 被注释的字符串必须是一个有效的url |
| @SafeHtml(whitelistType=, additionalTags=) | 被注解的元素检查是否标注值包含恶意的片段 |
- @Max、@Min接受一个Long类型的值
- @DecimalMax、@DecimalMin接受一个字符串类型的值(BigDecimal的字符串表示形式,因此可以是小数)
- 数字超过Long.MAX_VALUE或Long.MIN_VALUE以下或者数字是小数,@DecimalMax、@DecimalMin是唯一的选择。
实例1
@Data
public class AaSaveRequest extends BaseRequest {
private static final long serialVersionUID = -7895168538160321157L;
@NotEmpty(message = "用户名不能为空")
private String username;
@NotNull(message = "createTime不能为空")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
private Boolean delFlag;
}
@PostMapping("/save")
public WebResult save(@RequestBody @Valid AaSaveRequest saveRequest, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
//如果有校验错误,返回第一个校验信息
String defaultMessage = bindingResult.getFieldErrors().get(0).getDefaultMessage();
//将错误信息返回或者抛异常全局处理。
WebResult webResult = new WebResult();
webResult.setSuccess(false);
webResult.setMessage(defaultMessage);
return webResult;
}
BaseOperateResult operateResult = aaService.save(saveRequest);
if (!operateResult.isSuccess()) {
WebResult.error().message(operateResult.getErrorCode().getMessage());
}
return WebResult.ok();
}
实例2
/**
* 参数校验异常类
*/
public class ParameterCheckException extends RuntimeException {
private static final long serialVersionUID = -4163815498400849756L;
public ParameterCheckException(String message) {
super(message);
}
}
/**
* 全局异常处理类
*/
@Slf4j
@ResponseBody
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = ParameterCheckException.class)
private WebResult handlerParameterCheckException(ParameterCheckException e) {
//log.error("ParameterCheckException 异常 -> error = {}", e);
WebResult webResult = new WebResult();
webResult.setSuccess(false);
webResult.setCode(WebHttpCode.SERVICE_ERROR);
webResult.setMessage(e.getMessage());
return webResult;
}
}
@PostMapping("/save")
public WebResult save(@RequestBody @Valid AaSaveRequest saveRequest, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
//如果有校验错误,返回第一个校验信息
String defaultMessage = bindingResult.getFieldErrors().get(0).getDefaultMessage();
//将错误信息返回或者抛异常全局处理。
throw new ParameterCheckException(defaultMessage);
}
BaseOperateResult operateResult = aaService.save(saveRequest);
if (!operateResult.isSuccess()) {
WebResult.error().message(operateResult.getErrorCode().getMessage());
}
return WebResult.ok();
}

浙公网安备 33010602011771号