在 Java - servlet 3.0 这篇文章中我们大概了解了一下
Servlet 3.0,在日常web开发中我们一般都是使用SpringMVC框架,所以这里以Servlet 3.0注解的方式来搭建一下 SSM 框架

填写项目的 GAV 等信息:

项目的基本结构就是下面这样:

首先我们在 pom.xml 中配置 Spring、SpringMVC、Mybatis 相关的依赖,借助于 Maven 的依赖传递机制,我们只需要引入核心的依赖即可:
<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.0modelVersion>
<groupId>com.examplegroupId>
<artifactId>ssm-exampleartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
<spring.version>5.3.22spring.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.9version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.8version>
dependency>
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiterartifactId>
<version>5.8.2version>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.28version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>jakarta.servletgroupId>
<artifactId>jakarta.servlet-apiartifactId>
<version>4.0.4version>
<scope>providedscope>
dependency>
dependencies>
project>
业务都是不断完善的,架构也是慢慢演化的,所以这里的依赖不是固定的,有需要可以再添加
mysql 数据库 example,并新建一张 user 表CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`gender` tinyint(4) NULL DEFAULT NULL,
`nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SpringMVC从 SpringMVC 官方文档 中我们知道,不仅可以通过 web.xml 的方式来配置 DispatcherServlet,还可以通过 Java configuration 的方式来配置 DispatcherServlet。
ServletContext API 的形式配置public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
AbstractAnnotationConfigDispatcherServletInitializer 的形式配置public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { App1Config.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/app1/*" };
}
}
这里我们使用第二种方式:实现 AbstractAnnotationConfigDispatcherServletInitializer 来整合 SpringMVC,这种方式也是官方推荐的方式:

Root WebApplicationContext:@Configuration
public class SpringConfig {
}
Servlet WebApplicationContext:@Configuration
// SpringMVC 只需要扫描控制层即可
@ComponentScan(value = "com.example.controller")
// 开启 SpringMVC 高级配置
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
/**
* 配置静态资源访问
*
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
DispatcherServlet:public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
// 配置编码过滤器
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
// 配置处理请求方式的过滤器
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{
characterEncodingFilter,
hiddenHttpMethodFilter
};
}
}

从 SpringMVC 官方文档 中我们知道,Servlet 容器只需要扫描控制层即可,但是 Root 容器需要扫描 Service 层和 Repositiries 持久化层

@Configuration
@ComponentScan(value = "com.example", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = RestController.class),
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class),
})
public class SpringConfig {
...
}
druidjdbc.properties 来配置数据库连接信息jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.80.232:3306/example?serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
JdbcConsts 来读取配置信息@Data
@Component
public class JdbcConsts {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
}
当然了,只是这样并不能读取到 jdbc.properties 中的数据,我们还需要使用 @PropertySource 注解来把数据读取到内存中
@Configuration
@ComponentScan(value = "com.example", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = RestController.class),
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class),
})
// 加载文件到内存
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
...
}
@Configuration
@ComponentScan(value = "com.example", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = RestController.class),
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class),
})
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
@Bean
public DataSource dataSource(JdbcConsts jdbcConsts) {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(jdbcConsts.getDriver());
dataSource.setUrl(jdbcConsts.getUrl());
dataSource.setUsername(jdbcConsts.getUsername());
dataSource.setPassword(jdbcConsts.getPassword());
return dataSource;
}
}
首先创建数据表 user 对应的 Mybatis 需要的文件:User 实体、UserMapper 接口、UserMapper.xml

SqlSessionFactory@Configuration
@ComponentScan(value = "com.example", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = RestController.class),
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class),
})
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
@Bean
public DataSource dataSource(JdbcConsts jdbcConsts) {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(jdbcConsts.getDriver());
dataSource.setUrl(jdbcConsts.getUrl());
dataSource.setUsername(jdbcConsts.getUsername());
dataSource.setPassword(jdbcConsts.getPassword());
return dataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
System.out.println(dataSource);
sqlSessionFactoryBean.setDataSource(dataSource);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setTypeAliasesPackage("com.example.domain");
//sqlSessionFactoryBean.setConfigLocation();
//sqlSessionFactoryBean.setPlugins();
Properties properties = new Properties();
properties.setProperty("mapUnderscoreToCamelCase", "true");
sqlSessionFactoryBean.setConfigurationProperties(properties);
try {
sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mapper/*.xml"));
return sqlSessionFactoryBean.getObject();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
mapper 扫描@Configuration
@ComponentScan(value = "com.example", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = RestController.class),
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class),
})
@PropertySource("classpath:jdbc.properties")
// 扫描 Mybatis Mapper 层
@MapperScan(basePackages = "com.example.mapper")
public class SpringConfig {
...
}
...
@EnableTransactionManagement
public class SpringConfig {
...
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("add")
public Integer add(@RequestBody User user) {
return userService.add(user);
}
}
注意:这里需要使用到
SpringMVC的数据绑定功能,所以需要添加jackson-databind依赖。
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>x.x.xversion>
dependency>
可以配置分页插件 PageHelper,参考:Mybatis - PageHelper 分页插件
这一部分代码比较多,就不粘贴在这里了,有需要的朋友可以从 Git 地址 中拉取代码