千家信息网

SpringMVC有什么用

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,这篇文章主要为大家展示了"SpringMVC有什么用",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"SpringMVC有什么用"这篇文章吧。概述为了了解Sp
千家信息网最后更新 2025年12月02日SpringMVC有什么用

这篇文章主要为大家展示了"SpringMVC有什么用",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"SpringMVC有什么用"这篇文章吧。

概述

为了了解SpringMVC,先看一个流程示意图:

从流程图中,我们可以看到:

  • 接收前端传过来Request请求。
  • 根据映射路径找到对应的处理器处理请求,处理完成之后返回ModelAndView。
  • 进行视图解析,视图渲染,返回响应结果。

总结就是:参数接收,定义映射路径,页面跳转,返回响应结果

当然这只是最基本的核心功能,除此之外还可以定义拦截器,全局异常处理,文件上传下载等等。

一、搭建项目

在以前的老项目中,因为还没有SpringBoot,没有自动配置,所以需要使用web.xml文件去定义一个DispatcherServlet。现在互联网应用基本上都使用SpringBoot,所以我就直接使用SpringBoot进行演示。很简单,引入依赖即可:


org.springframework.boot
spring-boot-starter-web

二、定义Controller

使用SpringMVC定义Controller处理器,总共有五种方式。

2.1 实现Controller接口

早期的SpringMVC是通过这种方式定义:

/**
* @author Ye Hongzhi 公众号:java技术爱好者
* @name DemoController
* @date 2020-08-25 22:28
**/
@org.springframework.stereotype.Controller("/demo/controller")
public class DemoController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//业务处理
return null;
}
}

2.2 实现HttpRequestHandler接口

跟第一种方式差不多,也是通过实现接口的方式:

/**
* @author Ye Hongzhi 公众号:java技术爱好者
* @name HttpDemoController
* @date 2020-08-25 22:45
**/
@Controller("/http/controller")
public class HttpDemoController implements HttpRequestHandler{
@Override
public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
//业务处理
}
}

2.3 实现Servlet接口

这种方式已经不推荐使用了,不过从这里可以看出SpringMVC的底层使用的还是Servlet

@Controller("/servlet/controller")
public class ServletDemoController implements Servlet {
//以下是Servlet生命周期方法
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}

@Override
public ServletConfig getServletConfig() {
return null;
}

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}

@Override
public String getServletInfo() {
return null;
}

@Override
public void destroy() {
}
}

因为不推荐使用这种方式,所以默认是不加载这种适配器的,需要加上:

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {

@Bean
public SimpleServletHandlerAdapter simpleServletHandlerAdapter() {
return new SimpleServletHandlerAdapter();
}
}

2.4 使用@RequestMapping

这种方式是最常用的,因为上面那些方式定义需要使用一个类定义一个路径,就会导致产生很多类。使用注解就相对轻量级一些。

@Controller
@RequestMapping("/requestMapping/controller")
public class RequestMappingController {

@RequestMapping("/demo")
public String demo() {
return "HelloWord";
}
}

2.4.1 支持Restful风格

而且支持Restful风格,使用method属性定义对资源的操作方式:

 @RequestMapping(value = "/restful", method = RequestMethod.GET)
public String get() {
//查询
return "get";
}

@RequestMapping(value = "/restful", method = RequestMethod.POST)
public String post() {
//创建
return "post";
}

@RequestMapping(value = "/restful", method = RequestMethod.PUT)
public String put() {
//更新
return "put";
}

@RequestMapping(value = "/restful", method = RequestMethod.DELETE)
public String del() {
//删除
return "post";
}

2.4.2 支持Ant风格

 //匹配 /antA 或者 /antB 等URL
@RequestMapping("/ant?")
public String ant() {
return "ant";
}

//匹配 /ant/a/create 或者 /ant/b/create 等URL
@RequestMapping("/ant/*/create")
public String antCreate() {
return "antCreate";
}

//匹配 /ant/create 或者 /ant/a/b/create 等URL
@RequestMapping("/ant/**/create")
public String antAllCreate() {
return "antAllCreate";
}

2.5 使用HandlerFunction

最后一种是使用HandlerFunction函数式接口,这是Spring5.0后引入的方式,主要用于做响应式接口的开发,也就是Webflux的开发。

有兴趣的可以网上搜索相关资料学习,这个讲起来可能要很大篇幅,这里就不赘述了。

三、接收参数

定义完Controller之后,需要接收前端传入的参数,怎么接收呢。

3.1 接收普通参数

在@RequestMapping映射方法上写上接收参数名即可:

@RequestMapping(value = "/restful", method = RequestMethod.POST)
public String post(Integer id, String name, int money) {
System.out.println("id:" + id + ",name:" + name + ",money:" + money);
return "post";
}

3.2 @RequestParam参数名绑定

如果不想使用形参名称作为参数名称,可以使用@RequestParam进行参数名称绑定:

 /**
* value: 参数名
* required: 是否request中必须包含此参数,默认是true。
* defaultValue: 默认参数值
*/
@RequestMapping(value = "/restful", method = RequestMethod.GET)
public String get(@RequestParam(value = "userId", required = false, defaultValue = "0") String id) {
System.out.println("id:" + id);
return "get";
}

3.3 @PathVariable路径参数

通过@PathVariable将URL中的占位符{xxx}参数映射到操作方法的入参。演示代码如下:

@RequestMapping(value = "/restful/{id}", method = RequestMethod.GET)
public String search(@PathVariable("id") String id) {
System.out.println("id:" + id);
return "search";
}

3.4 @RequestHeader绑定请求头属性

获取请求头的信息怎么获取呢?

使用@RequestHeader注解,用法和@RequestParam类似:

 @RequestMapping("/head")
public String head(@RequestHeader("Accept-Language") String acceptLanguage) {
return acceptLanguage;
}

3.5 @CookieValue绑定请求的Cookie值

获取Request中Cookie的值:

 @RequestMapping("/cookie")
public String cookie(@CookieValue("_ga") String _ga) {
return _ga;
}

3.6 绑定请求参数到POJO对象

定义了一个User实体类:

public class User {
private String id;
private String name;
private Integer age;
//getter、setter方法
}

定义一个@RequestMapping操作方法:

 @RequestMapping("/body")
public String body(User user) {
return user.toString();
}

只要请求参数与属性名相同自动填充到user对象中:

3.6.1 支持级联属性

现在多了一个Address类存储地址信息:

public class Address {
private String id;
private String name;
//getter、setter方法
}

在User中加上address属性:

public class User {
private String id;
private String name;
private Integer age;
private Address address;
//getter、setter方法
}

传参时只要传入address.name、address.id即会自动填充:

3.6.2 @InitBinder解决接收多对象时属性名冲突

如果有两个POJO对象拥有相同的属性名,不就产生冲突了吗?比如刚刚的user和address,其中他们都有id和name这两个属性,如果同时接收,就会冲突:

 //user和address都有id和name这两个属性 
@RequestMapping(value = "/twoBody", method = RequestMethod.POST)
public String twoBody(User user, Address address) {
return user.toString() + "," + address.toString();
}

这时就可以使用@InitBinder绑定参数名称:

 @InitBinder("user")
public void initBindUser(WebDataBinder webDataBinder) {
webDataBinder.setFieldDefaultPrefix("u.");
}

@InitBinder("address")
public void initBindAddress(WebDataBinder webDataBinder) {
webDataBinder.setFieldDefaultPrefix("addr.");
}

3.6.3 @Requestbody自动解析JSON字符串封装到对象

前端传入一个json字符串,自动转换成pojo对象,演示代码:

 @RequestMapping(value = "/requestBody", method = RequestMethod.POST)
public String requestBody(@RequestBody User user) {
return user.toString();
}

注意的是,要使用POST请求,发送端的Content-Type设置为application/json,数据是json字符串

甚至有一些人喜欢用一个Map接收:

但是千万不要用Map接收,否则会造成代码很难维护,后面的老哥估计看不懂你这个Map里面有什么数据,所以最好还是定义一个POJO对象。

四、参数类型转换

实际上,SpringMVC框架本身就内置了很多类型转换器,比如你传入字符串的数字,接收的入参定为int,long类型,都会自动帮你转换。

就在包org.springframework.core.convert.converter下,如图所示:

有的时候如果内置的类型转换器不足够满足业务需求呢,怎么扩展呢,很简单,看我操作。什么是Java技术爱好者(战术后仰)。

首先有样学样,内置的转换器实现Converter接口,我也实现:

public class StringToDateConverter implements Converter {
@Override
public Date convert(String source) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
//String转换成Date类型
return sdf.parse(source);
} catch (Exception e) {
//类型转换错误
e.printStackTrace();
}
return null;
}
}

接着把转换器注册到Spring容器中:

@Configuration
public class ConverterConfig extends WebMvcConfigurationSupport {
@Override
protected void addFormatters(FormatterRegistry registry) {
//添加类型转换器
registry.addConverter(new StringToDateConverter());
}
}

接着看测试,所有的日期字符串,都自动被转换成Date类型了,非常方便:

五、页面跳转

在前后端未分离之前,页面跳转的工作都是由后端控制,采用JSP进行展示数据。虽然现在互联网项目几乎不会再使用JSP,但是我觉得还是需要学习一下,因为有些旧项目还是会用JSP,或者需要重构。

如果你在RequestMapping方法中直接返回一个字符串是不会跳转到指定的JSP页面的,需要做一些配置。

第一步,加入解析jsp的Maven配置。


org.apache.tomcat.embed
tomcat-embed-jasper
7.0.59


javax.servlet
jstl

第二步,添加视图解析器。

@Configuration
public class WebAppConfig extends WebMvcConfigurerAdapter {
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}
}

第三步,设置IDEA的配置。

第四步,创建jsp页面。

第五步,创建Controller控制器。

@Controller
@RequestMapping("/view")
public class ViewController {
@RequestMapping("/hello")
public String hello() throws Exception {
return "hello";
}
}

这样就完成了,启动项目,访问/view/hello就看到了:

就是这么简单,对吧

六、@ResponseBody

如果采用前后端分离,页面跳转不需要后端控制了,后端只需要返回json即可,怎么返回呢?

使用@ResponseBody注解即可,这个注解会把对象自动转成json数据返回。

@ResponseBody注解可以放在类或者方法上,源码如下:

//用在类、方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}

演示一下:

@RequestMapping("/userList")
@ResponseBody
public List userList() throws Exception {
List list = new ArrayList<>();
list.add(new User("1","姚大秋",18));
list.add(new User("2","李星星",18));
list.add(new User("3","冬敏",18));
return list;
}

测试一下/view/userList:

七、@ModelAttribute

@ModelAttribute用法比较多,下面一一讲解。

7.1 用在无返回值的方法上

在Controller类中,在执行所有的RequestMapping方法前都会先执行@ModelAttribute注解的方法。

@Controller
@RequestMapping("/modelAttribute")
public class ModelAttributeController {
//先执行这个方法
@ModelAttribute
public void modelAttribute(Model model){
//在request域中放入数据
model.addAttribute("userName","公众号:java技术爱好者");
}

@RequestMapping("/index")
public String index(){
//跳转到inex.jsp页面
return "index";
}
}

index.jsp页面如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


首页



${userName}




相当于一个Controller的拦截器一样,在执行RequestMapping方法前先执行@ModelAttribute注解的方法。所以要慎用。

启动项目,访问/modelAttribute/index可以看到:

即使在index()方法中没有放入userName属性值,jsp页面也能获取到,因为在执行index()方法之前的modelAttribute()方法已经放入了。

7.2 放在有返回值的方法上

其实调用顺序是一样,也是在RequestMapping方法前执行,不同的在于,方法的返回值直接帮你放入到Request域中。

//放在有参数的方法上
@ModelAttribute
public User userAttribute() {
//相当于model.addAttribute("user",new User("1", "Java技术爱好者", 18));
return new User("1", "Java技术爱好者", 18);
}

@RequestMapping("/user")
public String user() {
return "user";
}

创建一个user.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


首页


ID:${user.id}


名称:${user.name}


年龄:${user.age}岁




测试一下:

放入Request域中的属性值默认是类名的首字母小写驼峰写法,如果你想自定义呢?很简单,可以这样写:

//自定义属性名为"u"
@ModelAttribute("u")
public User userAttribute() {
return new User("1", "Java技术爱好者", 18);
}
/**
JSP就要改成这样写:

ID:${u.id}


名称:${u.name}


年龄:${u.age}岁


*/

7.3 放在RequestMapping方法上

@Controller
@RequestMapping("/modelAttribute")
public class ModelAttributeController {

@RequestMapping("/jojo")
@ModelAttribute("attributeName")
public String jojo() {
return "JOJO!我不做人了!";
}
}

这种情况下RequestMapping方法的返回的值就不是JSP视图了。而是把返回值放入Request域中的属性值,属性名为attributeName。视图则是RequestMapping注解上的URL,所以创建一个对应的JSP页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


首页


${attributeName}




测试一下:

7.4 放在方法入参上

放在入参上,意思是从前面的Model中提取出对应的属性值,当做入参传入方法中使用。如下所示:

@ModelAttribute("u")
public User userAttribute() {
return new User("1", "Java技术爱好者", 18);
}

@RequestMapping("/java")
public String user1(@ModelAttribute("u") User user) {
//拿到@ModelAttribute("u")方法返回的值,打印出来
System.out.println("user:" + user);
return "java";
}

测试一下:

八、拦截器

拦截器算重点内容了,很多时候都要用拦截器,比如登录校验,权限校验等等。SpringMVC怎么添加拦截器呢?

很简单,实现HandlerInterceptor接口,接口有三个方法需要重写。

  • preHandle():在业务处理器处理请求之前被调用。预处理。
  • postHandle():在业务处理器处理请求执行完成后,生成视图之前执行。后处理。
  • afterCompletion():在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);

自定义的拦截器,实现的接口HandlerInterceptor:

public class DemoInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//预处理,返回true则继续执行。如果需要登录校验,校验不通过返回false即可,通过则返回true。
System.out.println("执行preHandle()方法");
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//后处理
System.out.println("执行postHandle()方法");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//在DispatcherServlet完全处理完请求后被调用
System.out.println("执行afterCompletion()方法");
}
}

然后把拦截器添加到Spring容器中:

@Configuration
public class ConverterConfig extends WebMvcConfigurationSupport {

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new DemoInterceptor()).addPathPatterns("/**");
}
}

/**代表所有路径,测试一下:

九、全局异常处理

SpringMVC本身就对一些异常进行了全局处理,所以有内置的异常处理器,在哪里呢?

HandlerExceptionResolver接口的类图就知道了:

从类图可以看出有四种异常处理器:

  • DefaultHandlerExceptionResolver,默认的异常处理器。根据各个不同类型的异常,返回不同的异常视图。
  • SimpleMappingExceptionResolver,简单映射异常处理器。通过配置异常类和view的关系来解析异常。
  • ResponseStatusExceptionResolver,状态码异常处理器。解析带有 @ResponseStatus注释类型的异常。
  • ExceptionHandlerExceptionResolver,注解形式的异常处理器。对 @ExceptionHandler注解的方法进行异常解析。

第一个默认的异常处理器是内置的异常处理器,对一些常见的异常处理,一般来说不用管它。后面的三个才是需要注意的,是用来扩展的。

9.1 SimpleMappingExceptionResolver

翻译过来就是简单映射异常处理器。用途是,我们可以指定某种异常,当抛出这种异常之后跳转到指定的页面。请看演示。

第一步,添加spring-config.xml文件,放在resources目录下,文件名见文知意即可:


xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">









err





第二步,在启动类加载xml文件:

@SpringBootApplication
@ImportResource("classpath:spring-config.xml")
public class SpringmvcApplication {

public static void main(String[] args) {
SpringApplication.run(SpringmvcApplication.class, args);
}

}

第三步,在webapp目录下创建一个err.jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


异常页面


出现异常,这是一张500页面




<%-- 打印异常到页面上 --%>
<% Exception ex = (Exception)request.getAttribute("ex"); %>


<%=ex.getMessage()%>

<% ex.printStackTrace(new java.io.PrintWriter(out)); %>


这样就完成了,写一个接口测试一下:

@Controller
@RequestMapping("/exception")
public class ExceptionController {
@RequestMapping("/index")
public String index(String msg) throws Exception {
if ("null".equals(msg)) {
//抛出空指针异常
throw new NullPointerException();
}
return "index";
}
}

效果如下:

这种异常处理器,在现在前后端分离的项目中几乎已经看不到了。

9.2 ResponseStatusExceptionResolver

这种异常处理器主要用于处理带有@ResponseStatus注释的异常。请看演示代码:

自定义一个异常类,并且使用@ResponseStatus注解修饰:

//HttpStatus枚举有所有的状态码,这里返回一个400的响应码
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class DefinedException extends Exception{
}

写一个Controller接口进行测试:

@RequestMapping("/defined")
public String defined(String msg) throws Exception {
if ("defined".equals(msg)) {
throw new DefinedException();
}
return "index";
}

启动项目,测试一下,效果如下:

9.3 ExceptionHandlerExceptionResolver

注解形式的异常处理器,这是用得最多的。使用起来非常简单方便。

第一步,定义自定义异常BaseException:

public class BaseException extends Exception {
public BaseException(String message) {
super(message);
}
}

第二步,定义一个错误提示实体类ErrorInfo:

public class ErrorInfo {
public static final Integer OK = 0;
public static final Integer ERROR = -1;
private Integer code;
private String message;
private String url;
//getter、setter
}

第三步,定义全局异常处理类GlobalExceptionHandler:

//这里使用了RestControllerAdvice,是@ResponseBody和@ControllerAdvice的结合
//会把实体类转成JSON格式的提示返回,符合前后端分离的架构
@RestControllerAdvice
public class GlobalExceptionHandler {

//这里自定义了一个BaseException,当抛出BaseException异常就会被此方法处理
@ExceptionHandler(BaseException.class)
public ErrorInfo errorHandler(HttpServletRequest req, BaseException e) throws Exception {
ErrorInfo r = new ErrorInfo();
r.setMessage(e.getMessage());
r.setCode(ErrorInfo.ERROR);
r.setUrl(req.getRequestURL().toString());
return r;
}
}

完成之后,写一个测试接口:

@RequestMapping("/base")
public String base(String msg) throws Exception {
if ("base".equals(msg)) {
throw new BaseException("测试抛出BaseException异常,欧耶!");
}
return "index";
}

启动项目,测试:

以上是"SpringMVC有什么用"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

处理 方法 参数 处理器 属性 页面 接口 注解 测试 方式 类型 项目 对象 技术 爱好者 拦截器 名称 字符 字符串 视图 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 河北数据软件开发服务号选择 985网络安全专业就业 社区网络安全普及教育活动简报 普陀区机电软件开发口碑推荐 c 数据库入门 网络安全产品审查 php基础学什么软件开发 进口网络安全整机厂家 梦想城镇服务器怎么样 全新的软件开发 上海如何利用社交软件开发客户 开展网络安全意识教育培训 计算机网络技术收文科生吗 网络安全攻击和破坏 网络安全入侵检测工具 数据库表多对多关系注意事项 专业供应的眼镜行业软件开发 网络安全法施行什么制度 国家电网网络安全标语 服务器性能排名 网络安全促进行业升级 服务器安全组绝对安全吗 慧慧网络安全画饭圈 中国网络安全大会是什么时候 网络安全入侵检测工具 查找文献常用的数据库 网页服务器如何确保内网安全 火影忍者手游服务器无法连接 开启数据网络无法连接服务器 ftp服务器创建用户
0