本示例集成 Spring IOC、AOP、事务、MyBatis、Maven、MySQL、简易 MVC,实现图书增删改查,作为 SSM 框架整合的标准范式。项目结构清晰,可直接作为脚手架扩展。
src/main/java ├── com.zhangguo.bookstore │ ├── entities # Book 实体 │ ├── mapper # BookDAO 接口 + BookMapper.xml │ ├── service # BookService 业务层 │ ├── action # BaseController + BookController + CtxUtil │ └── test # JUnit 测试 src/main/webapp ├── WEB-INF │ ├── web.xml │ ├── ListBook.jsp │ ├── AddBook.jsp │ └── EditBook.jsp ├── styles/main.css └── index.jsp resources ├── applicationContext.xml ├── db.properties └── log4j2.xml

jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=UTF-8 jdbc.uid=root jdbc.pwd=root
<beans ...>
<!-- 1. 属性占位符 -->
<context:property-placeholder location="classpath*:db.properties" />
<!-- 2. C3P0 数据源 -->
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.uid}" />
<property name="password" value="${jdbc.pwd}" />
<property name="acquireIncrement" value="5" />
<property name="initialPoolSize" value="10" />
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
</bean>
<!-- 3. SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<property name="typeAliasesPackage" value="com.zhangguo.bookstore.entities" />
<property name="mapperLocations" value="classpath*:com/zhangguo/bookstore/mapper/*Mapper.xml" />
</bean>
<!-- 4. Mapper 扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
<property name="basePackage" value="com.zhangguo.bookstore.mapper" />
</bean>
<!-- 5. 声明式事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 6. 组件扫描 -->
<context:component-scan base-package="com.zhangguo.bookstore" />
<!-- 7. AspectJ 自动代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
</beans>
public class Book {
private int id;
private String title;
private double price;
private Date publishDate;
// getter/setter + 构造器
}
public interface BookDAO {
List<Book> getAllBooks();
Book getBookById(@Param("id") int id);
int add(Book entity);
int delete(int id);
int update(Book entity);
}
<mapper namespace="com.zhangguo.bookstore.mapper.BookDAO">
<select id="getAllBooks" resultType="Book">select id,title,price,publishDate from books</select>
<select id="getBookById" resultType="Book">select id,title,price,publishDate from books where id=#{id}</select>
<insert id="add">insert into books(title,price,publishDate) values(#{title},#{price},#{publishDate})</insert>
<delete id="delete">delete from books where id=#{id}</delete>
<update id="update">update books set title=#{title},price=#{price},publishDate=#{publishDate} where id=#{id}</update>
</mapper>
@Service
public class BookService {
@Resource BookDAO bookdao;
public List<Book> getAllBooks() { return bookdao.getAllBooks(); }
public Book getBookById(int id) { return bookdao.getBookById(id); }
public int add(Book entity) throws Exception {
if (entity.getTitle() == null || entity.getTitle().isEmpty())
throw new Exception("书名必填");
return bookdao.add(entity);
}
@Transactional
public int add(Book e1, Book e2) { // 事务测试:同名书第二次插入会回滚
return bookdao.add(e1) + bookdao.add(e2);
}
// delete/update 略
}
public class BaseController extends HttpServlet {
protected void service(HttpServletRequest req, HttpServletResponse resp) {
String act = req.getParameter("act");
if (act == null) act = "execute";
try {
Method m = getClass().getMethod(act, HttpServletRequest.class, HttpServletResponse.class);
String target = (String) m.invoke(this, req, resp);
if (target.startsWith("redirect:")) resp.sendRedirect(target.substring(9));
else req.getRequestDispatcher(target).forward(req, resp);
} catch (Exception e) { resp.sendError(400, e.getMessage()); }
}
}
BookController 继承 BaseController,实现 ListBook、Delete、Deletes、AddBook/AddBookPost、EditBook/EditBookPost 等 Action,配合 JSP 完成增删改查闭环。

<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </context-param>
@Component
public class CtxUtil implements ApplicationContextAware {
public static ApplicationContext ctx;
@Override public void setApplicationContext(ApplicationContext c) { ctx = c; }
public static <T> T getBean(Class<T> clazz) { return ctx.getBean(clazz); }
}
示例覆盖 Spring IOC、AOP、事务、MyBatis Mapper 扫描、简易 MVC 分发、JSP+JSTL 视图、Maven 标准目录。后续可扩展:SpringMVC 替代简易 MVC、Validator 校验、RESTful API、前后端分离(Vue/React)、Docker 部署。