本系列目標是構建一個完整的用戶註冊登入專案,技術棧:IntelliJ IDEA + Spring 4.3.1 + MyBatis 3.4 + MySQL + Maven。本篇聚焦於純 Java 代碼配置 IOC 容器與MyBatis 整合,摒棄傳統 XML 配置,體驗現代 Spring 開發模式。
建立 maven-webapp 專案,目錄結構遵循標準約定:
src ├─ main │ ├─ java │ │ └─ com.everSeeker │ │ ├─ config // Java Config 類 │ │ ├─ dao // MyBatis Mapper 接口 │ │ ├─ entity // 實體類 │ │ └─ web // Controller 等 │ └─ resources │ ├─ mapper // MyBatis XML 映射文件 │ ├─ db.properties // 數據源配置 │ ├─ mybatis.xml // MyBatis 核心配置 │ └─ spring-mybatis.xml // Spring-MyBatis 整合配置 └─ test
<properties>
<spring.version>4.3.1.RELEASE</spring.version>
</properties>
<dependencies>
<!-- Spring Core -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency>
<!-- MyBatis -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.1</version></dependency>
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.3.0</version></dependency>
<!-- Database -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>6.0.3</version></dependency>
<dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1.2</version></dependency>
<!-- Validation -->
<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>1.1.0.Final</version></dependency>
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>5.2.4.Final</version></dependency>
<!-- Servlet/JSP -->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version></dependency>
<dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency>
</dependencies>
db.mysql.driverClass=com.mysql.jdbc.Driver db.mysql.jdbcUrl=jdbc:mysql://localhost:3306/register_notice?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true db.mysql.user=root db.mysql.password=333 # C3P0 連接池參數 db.minPoolSize=10 db.maxPoolSize=100 db.initialPoolSize=20 db.maxIdleTime=60 db.acquireIncrement=5 db.maxStatements=100 db.idleConnectionTestPeriod=60 db.acquireRetryAttempts=30 db.breakAfterAcquireFailure=true db.testConnectionOnCheckout=false
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.everSeeker.entity" />
</typeAliases>
</configuration>
採用包掃描方式自動註冊別名,省去逐個 <typeAlias> 配置。
<beans ...>
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${db.mysql.driverClass}"/>
<property name="jdbcUrl" value="${db.mysql.jdbcUrl}"/>
<property name="user" value="${db.mysql.user}"/>
<property name="password" value="${db.mysql.password}"/>
<!-- C3P0 連接池屬性注入省略 -->
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dataSource"
p:configLocation="classpath:mybatis.xml"
p:mapperLocations="classpath*:mapper/*Mapper.xml"/>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.everSeeker.dao"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
</beans>
關鍵點:
context:property-placeholder 優先載入屬性文件,確保後續 Bean 定義能解析 ${...} 佔位符。mapperLocations="classpath*:mapper/*Mapper.xml" 使用 classpath* 掃描多模塊下的映射文件。MapperScannerConfigurer 自動將 Mapper 接口掃描為 Spring Bean,無需手動配置。@Transactional 註解驅動,proxy-target-class="true" 強制使用 CGLIB 代理類而非 JDK 動態代理。package com.everSeeker.entity;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.UUID;
public class User {
@Size(min = 32, max = 32, message = "uuid 應為 32 位字符串")
private String id;
@Size(min = 1, max = 32, message = "賬號長度 1-32 位")
private String username;
@NotEmpty(message = "密碼不能為空")
private String password;
@NotEmpty(message = "email 不能為空")
@Email(message = "email 格式不正確")
private String email;
@Size(min = 11, max = 11, message = "手機號長度 11 位")
private String cellphone;
private long regDate;
public User() {
this.id = UUID.randomUUID().toString().replaceAll("-", "");
this.regDate = 0;
}
// 多構造器、Getter/Setter、toString 省略
}
package com.everSeeker.dao;
import com.everSeeker.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserDao {
void addUser(User user);
User getUserByUsername(String username);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.everSeeker.dao.UserDao">
<resultMap id="ResultMapUser" type="com.everSeeker.entity.User"></resultMap>
<insert id="addUser" parameterType="User">
INSERT INTO user(id, username, password, email, cellphone, regDate)
VALUES(#{id}, #{username}, #{password}, #{email}, #{cellphone}, #{regDate})
</insert>
<select id="getUserByUsername" parameterType="String" resultMap="ResultMapUser">
SELECT * FROM user WHERE username=#{username}
</select>
</mapper>
避坑提示:Mapper XML 必須置於
src/main/resources目錄,若放在src/main/java下 Maven 編譯不會複製資源文件,導致運行時找不到映射文件報錯。
package com.everSeeker.config;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.type.filter.RegexPatternTypeFilter;
import java.util.regex.Pattern;
@Configuration
@ComponentScan(basePackages = {"com.everSeeker"},
excludeFilters = @Filter(type = FilterType.CUSTOM, value = RootConfig.WebPackage.class))
@ImportResource({"classpath:spring-mybatis.xml"})
public class RootConfig {
public static class WebPackage extends RegexPatternTypeFilter {
public WebPackage() {
super(Pattern.compile("com\\.everSeeker\\.web"));
}
}
}
解析:
@Configuration:標識配置類,等同於 <beans>。@ComponentScan:啟用組件掃描,排除 web 包(Controller 由 Servlet 容器管理)。@ImportResource:導入 XML 配置(MyBatis 整合暫時保留 XML,後續可全 Java Config 化)。package com.everSeeker.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration;
import java.io.IOException;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected String[] getServletMappings() {
return new String[]{"/"}; // DispatcherServlet 攔截所有請求
}
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class}; // 業務層 Bean
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebConfig.class}; // Web 層 Bean
}
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
// 文件上傳限制:單文件 2MB,總請求 4MB,臨時目錄 /tmp/uploads
registration.setMultipartConfig(new MultipartConfigElement("/tmp/uploads", 2097152, 4194304, 0));
}
}
package com.everSeeker.config;
import org.springframework.context.annotation.*;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import java.io.IOException;
@Configuration
@EnableWebMvc
@ComponentScan("com.everSeeker.web")
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
@Bean
public StandardServletMultipartResolver multipartResolver() throws IOException {
return new StandardServletMultipartResolver();
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable(); // 靜態資源由容器默認 Servlet 處理
}
}
本篇完成了:
@Configuration、@ComponentScan、@ImportResource 的純 Java Config IOC 容器構建。AbstractAnnotationConfigDispatcherServletInitializer 實現零 web.xml 部署。下一篇將引入 Spring MVC Controller 實現用戶註冊接口,並整合 Hibernate Validator 完成表單驗證。

