1.简介
SpringMVC 是一种基于 Java 实现的 MVC 模型的轻量级 Web 框架,可以用它替换 Servlet 技术。
。
2.快速入门
先用 Maven 创建一个 Web 应用,具体方式可以参考。
2.1.依赖
开发的 Web 应用最终要部署在 Tomcat 上,依赖于 Servlet API。所以需要添加相关依赖:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
要注意,这里 servlet-api 的版本与 Tomcat 版本是相关的,具体可以查看。
这里的 scope 范围是 provided,因为 Tomcat 自己就包含 servlet-api,打包时必须排除,否则会引发冲突。
其中 Servlet Spec Servlet 一列就是对应的 Servlet-api 版本,这里因为项目整合了 Tomcat7 的 Maven 插件,所以在开发阶段是运行在 Tomcat7 上的,这里就是用 3.0+ 的 servlet-api 依赖。
添加 Spring MVC 依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
可以看到,spring-webmvc 是包含了 spring-context 依赖的:
所以这里我们不需要额外添加对 spring-context 依赖的引用。
因为这里使用 Spring MVC 进行配置和管理 Web 应用,所以可以删除/WEB-INF/web.xml
配置文件。
2.2.配置类
添加配置类:
"cn.icexmoon.mvcdemo.controller")
(public class SpringMvcConfig {
}
2.3.Controller
添加 Controller:
public class UserController {
"/save")
(
public String save() {
return "{'result':true,'msg':'user saved.'}";
}
}
2.4.ServletInitializer
要让 Tomcat 能正确加载 Web 应用,还需要添加一个 Servlet 容器初始化类:
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
/**
* 加载 Spring MVC 容器配置
* @return
*/
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringMvcConfig.class);
return context;
}
/**
* 哪些路径请求由 Spring MVC 进行处理
* @return
*/
protected String[] getServletMappings() {
return new String[]{"/"};
}
/**
* 加载 Spring 容器配置
* @return
*/
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
Spring 提供一个抽象类AbstractDispatcherServletInitializer
,通过实现这个类的相应方法,我们可以让 Tomcat 的 Web 容器加载 Spring MVC 容器,并告诉 Tomcat 哪些请求路径由 Spring MVC 进行响应。
2.5.测试
通过插件启动项目。
一切 OK 的话访问 Tomcat 页面(比如 http://localhost/save)就能看到响应。
如果出现 404 或其它错误,可以检查各种组件(包括 JDK)的版本是否兼容,比如 Spring 6 应当使用 Java 17 以上的版本, Spring 6 以下应当使用 Java 8(JDK 1.8)。Tomcat7 对应的 Java 版本是 7+,对应的 servlet-api 是 3.0 等等。
3.Bean 加载控制
上面的简单示例仅仅包含控制层代码,如果还包含服务层和持久层,就需要添加一个 Spring 容器来进行管理。
3.1.Spring 配置类
添加 Spring 配置类:
value = "cn.icexmoon.mvcdemo",
( excludeFilters = {
Filter(
. type = FilterType.ANNOTATION,
value = Controller.class
),
Filter(
. type = FilterType.ANNOTATION,
value = NoSpringScan.class)
})
"classpath:jdbc.properties")
(public class SpringConfig {
}
我们现在设想的是:Spring MVC 容器加载 controller 包下的 Bean,Spring 容器加载其余的 Bean。
所以这里需要在 Spring 的包扫描(@ComponentScan
)中设置排除,具体可以用excludeFilters
属性实现。
在这里除了排除@Controller
注解标记的 Bean,还额外添加了一个排除自定义注解@NoSpringScan
。这是因为我们还需要排除 Spring MVC 的配置类SpringMvcConfig
才行,否则就会因为SpringMvcConfig
中的包扫描导致 Spring 容器加载了 controller
包下的 Bean。
自定义注解:
ElementType.TYPE)
(RetentionPolicy.RUNTIME)
(public @interface NoSpringScan {
}
用自定义注解标记 Spring MVC 配置类:
"cn.icexmoon.mvcdemo.controller")
(public class SpringMvcConfig {
}
除了这种排除方式外,还可以选择让包扫描加载指定的包而非整个项目的包。
3.2.修改 ServletContainerInitConfig
在 Servlet 容器初始化类中添加 Spring 容器初始化内容:
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
// ...
/**
* 加载 Spring 容器配置
* @return
*/
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringConfig.class);
return context;
}
}
3.3.测试
之后就可以在代码中整合 MyBatis,并编写服务层和持久层代码,并最终在控制层中实现对服务层的调用。具体可以参考这篇。
示例:
@Controller
public class UserController {
// ...
@RequestMapping("/user/{id}")
@ResponseBody
public String getUserInfo(@PathVariable("id") Integer id) {
User user = userService.getById(id);
System.out.println(user);
return JSON.toJSONString(user);
}
}
再次部署应用后请求http://localhost/user/1
就能看到返回内容:
{"addr":"??","gender":"?","id":1,"password":"123","userName":"zhangsan"}
乱码是因为返回报文头中的报文格式和编码方式不对。
3.4.ServletInitializer
出了用AbstractDispatcherServletInitializer
创建 Servlet 容器初始化类以外,还可以用它的一个子类AbstractAnnotationConfigDispatcherServletInitializer
:
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* spring 容器的配置类
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
/**
* spring MVC 容器的配置类
* @return
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
/**
* 哪些请求由 spring MVC 进行处理和响应
* @return
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
代码会简洁一些。
The End,谢谢阅读。
可以从获取本文完整的代码示例。
文章评论