插件版本
Spring-5.2.3.RELEASE
struts2-core:2.5.30
Hibernate 5.4.11
创建项目
选择spring版本,选择下载依赖包
选择struts2 直接选择下载依赖包(会失败),可以先选择稍后处理;
选择hibernate版本,选择下载依赖包
点击 next
填写项目名称,点击finish
一. 引入依赖包
Spring-5.2.3.RELEASE --已下载
Hibernate 5.4.11 --已下载
struts2-spring-plugin-2.5.30.jar --struts2整合Spring所需jar
spring-web-5.2.3.RELEASE.jar
aspectjweaver-1.9.8.jar --处理事务和AOP所需的包
mysql-connector-java-8.0.22.jar --数据库依赖包
commons-dbcp-1.4.jar --连接池
commons-pool-1.5.4.jar
如下方式,可以下载添加依赖包
struts2-spring-plugin-2.5.30中依赖的Spring-4.3.26.RELEASE 移除,
下载spring-web-5.2.3.RELEASE.jar
至此依赖下载完成
二. 新增配置文件applicationContext.xml
右击 WEB-INF,新增配置文件 applicationContext.xml
编写applicationContext.xml 配置sessionFactory
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:33068/sshdemo?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC"></property>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
做如下添加
三. 修改配置文件web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置环境参数,指定Spring配置文件的位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<!--配置监听器,初始化Spring容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<display-name>demo</display-name>
<welcome-file-list>
<welcome-file>/index.jsp</welcome-file>
</welcome-file-list>
</web-app>
四. 新增package
五. 连接数据库,生成实体类
数据库sql
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userName` varchar(20) NOT NULL,
`trueName` varchar(20) NOT NULL,
`password` varchar(20) NOT NULL,
`role` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of usertable
-- ----------------------------
INSERT INTO `usertable` VALUES ('1', 'admin', 'admin', 'admin', '管理员');
INSERT INTO `usertable` VALUES ('2', '剑谪仙', '剑谪仙', 'admin', '学生');
INSERT INTO `usertable` VALUES ('3', '王五', '王五', 'admin', '学生');
INSERT INTO `usertable` VALUES ('6', '秦假仙', '秦假仙', 'qjx', '教师');
INSERT INTO `usertable` VALUES ('7', '素还真', '素还真', 'shz', '教师');
INSERT INTO `usertable` VALUES ('8', '风月主人', '风月主人', 'admin', '学生');
连接成功,出现下图;
ok后, com.test.ssh.entity包下生成 UserEntity 类
applicationContext.xml也修改了,
<!-- session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.connection.url">
<![CDATA[jdbc:mysql://localhost:33068/sshdemo?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false]]></prop>
<prop key="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.test.ssh.entity.UserEntity</value>
</list>
</property>
</bean>
六. 编写dao,sevice,action,jsp 代码
BaseDao代码
package com.test.ssh.dao;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import java.util.List;
public class BaseDao<T> extends HibernateDaoSupport {
// 新增数据
public void save(T entity) {
try
{
getHibernateTemplate().save(entity);
}
catch (Throwable e)
{
logger.error(e.getMessage(), e);
throw e;
}
}
// 删除数据
public void delete(T entity) {
try
{
getHibernateTemplate().delete(entity);
}
catch (Throwable e)
{
logger.error(e.getMessage(), e);
throw e;
}
}
// 修改数据
public void update(T entity) {
try
{
getHibernateTemplate().update(entity);
}
catch (Throwable e)
{
logger.error(e.getMessage(), e);
throw e;
}
}
// 查找数据
public List<T> find(String hql) {
try
{
List list = (List<T>) getHibernateTemplate().find(hql);
return list;
}
catch (Throwable e)
{
logger.error(e.getMessage(), e);
throw e;
}
}
// 查找数据
public List<T> find(String hql, Object... params) {
try
{
List list = (List<T>) getHibernateTemplate().find(hql, params);
return list;
}
catch (Throwable e)
{
logger.error(e.getMessage(), e);
throw e;
}
}
}
UserDao 代码
package com.test.ssh.dao;
import com.test.ssh.entity.UserEntity;
import java.util.List;
public class UserDao extends BaseDao<UserEntity> {
// 根据账号密码,查找用户
public UserEntity queryByUserName(String name, String pswd) {
String hql = "FROM com.test.ssh.entity.UserEntity u WHERE userName=?0 AND password=?1 ";
List<UserEntity> list = find(hql, name, pswd);
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
}
// 获取所有用户
public List<UserEntity> getAll() {
String hql = "FROM com.test.ssh.entity.UserEntity ";
return find(hql);
}
// 根据id查询用户
public UserEntity queryById(int id) {
String hql = "FROM com.test.ssh.entity.UserEntity u WHERE id=?0";
List<UserEntity> list = find(hql, id);
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
}
}
UserService 代码
package com.test.ssh.service;
import com.test.ssh.dao.UserDao;
import com.test.ssh.entity.UserEntity;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Transactional
public class UserService {
UserDao userDao;
// 根据账号密码,查找用户
public UserEntity queryByUserName(String name, String pswd) {
return userDao.queryByUserName(name, pswd);
}
// 新增用户
public int save(UserEntity user) {
userDao.save(user);
return user.getId();
}
// 删除用户
public void delete(UserEntity user) {
userDao.delete(user);
}
// 修改用户
public void update(UserEntity user) {
userDao.update(user);
}
// 获取所有用户
public List<UserEntity> getAll() {
return userDao.getAll();
}
// 根据id查询用户
public UserEntity queryById(int id) {
return userDao.queryById(id);
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
UserAction 代码
package com.test.ssh.action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.test.ssh.entity.UserEntity;
import com.test.ssh.service.UserService;
import java.util.List;
public class UserAction extends ActionSupport {
UserEntity user;
UserService userService;
// 登录
public String login() {
String name = user.getUserName();
String pswd = user.getPassword();
UserEntity u = userService.queryByUserName(name, pswd);
if (u == null) {
addFieldError("errMsg", "用户名或密码不正确!");
return "error";
} else {
return "userlist";
}
}
// 获取 修改或新增界面
public String modify() {
int id = user.getId();
if(id == 0){ // 新增
user = new UserEntity();
}else { // 修改
user = userService.queryById(id);
}
ActionContext.getContext().put("user", user);
return "modify";
}
// 保存数据,进行新增或修改 成功后返回列表页面
public String save() {
int id = user.getId();
if(id == 0){ // 新增
id = userService.save(user);
}else { // 修改
userService.update(user);
}
return "userlist";
}
// 删除数据, 成功后返回列表页面
public String delete() {
userService.delete(user);
return "userlist";
}
// 返回用户列表
public String getUserList() {
List<UserEntity> list = userService.getAll();
ActionContext.getContext().put("list", list);
return "userlist";
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
public UserService getUserService() {
return userService;
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}
index.jsp 代码
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%= basePath %>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>登录</title>
</head>
<body>
<div>
<s:form action="login" method="post" theme="simple">
<div class="login">
<div class="login_title">
用户登录
</div>
<fieldset>
<legend>账户信息</legend>
<p>
请输入用户账户信息进行登录,若没有账户,请先<a href="${pageContext.request.contextPath}/modify?user.id=0">注册</a>
</p>
<table>
<tr>
<td>用户名</td>
<td>
<s:textfield name="user.userName"></s:textfield><s:fielderror fieldName="user.userName"/>
</td>
</tr>
<tr>
<td>密码</td>
<td>
<s:password name="user.password"></s:password><s:fielderror fieldName="user.password"/>
</td>
</tr>
</table>
</fieldset>
<s:submit value="提 交" cssClass="login_submit"></s:submit>
<s:reset value="重置" cssClass="login_submit"></s:reset>
</div>
</s:form>
<s:if test="hasFieldErrors()">
<s:property value="fieldErrors['errMsg'][0]"/>
</s:if>
</div>
</body>
</html>
userlist.jsp 代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>成功</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.infotable {
margin: 0px auto;
border: 2px solid skyblue;
width: 80%;
}
tr,
td {
border: 1px solid black;
}
td {
text-align: center;
}
tr:first-child {
font-weight: 700;
}
</style>
<script src='http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js'></script>
<script type="text/javascript">
$(function(){
//删除用户
$(".delete").click(function(){
var str=this.lang.split("!");
if(!confirm("你确定要删除"+ str[1] +"这个用户吗?"))
{
return;
}
//jquery ajax方式请求action
$.post("${pageContext.request.contextPath}/delete",{"user.id":str[0]},function(){
location.href="${pageContext.request.contextPath}/getList";
alert("删除成功!")
});
<%--$.post("${pageContext.request.contextPath}/delete",{"user.id":str[0]});--%>
});
//修改用户
$(".modify").click(function(){
//为保证跳转的控制权在action中
location.href="${pageContext.request.contextPath}/modify?user.id=" + this.lang;
});
});
</script>
</head>
<body>
<h1>用户列表</h1>
<table class="infotable" cellspacing="0px" cellpadding="0px">
<tr>
<td>编号</td>
<td>姓名</td>
<td>账号</td>
<td>密码</td>
<td>角色</td>
<td>操作</td>
</tr>
<s:iterator value="list">
<tr>
<td><s:property value="id"/></td>
<td><s:property value="trueName"/></td>
<td><s:property value="userName"/></td>
<td><s:property value="password"/></td>
<td><s:property value="role"/></td>
<td>
<a href="#" class="modify" lang="0">新增</a>
<a href="#" class="modify" lang="<s:property value="id"/>">修改</a>
<a href="#" class="delete" lang="<s:property value="id"/>!<s:property value="userName"/>">删除</a>
</td>
</tr>
</s:iterator>
</table>
</body>
</html>
modify.jsp 代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>新增/编辑</h1>
<form method="post" action="${pageContext.request.contextPath}/save">
<li>
<label>编号</label>
<input type="text" name="user.id" value="<s:property value="#user.id"/>" readonly>
</li>
<li>
<label>姓名</label>
<input type="text" name="user.trueName" value="<s:property value="#user.trueName"/>">
</li>
<li>
<label>账号</label>
<input type="text" name="user.userName" value="<s:property value="#user.userName"/>">
</li>
<li>
<label>密码</label>
<input type="text" name="user.password" value="<s:property value="#user.password"/>">
</li>
<li>
<label>角色</label>
<input type="text" name="user.role" value="<s:property value="#user.role"/>">
</li>
<input type="submit" value="保存">
<a href="${pageContext.request.contextPath}/getList">取消</a>
</form>
</body>
</html>
struts.xml 代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
<constant name="struts.devMode" value="true"/>
<!-- struts.objectFactory=spring struts2框架就会把bean转发给spring来创建,装配,注入。
但是bean创建完成之后,还是由struts容器来管理其生命周期。
需要依赖包 struts2-spring-plugin-2.5.30.jar 版本和struts2一致 -->
<constant name="struts.objectFactory" value="spring" />
<!-- 用户管理 -->
<package name="userManage" extends="struts-default">
<!-- 登录 返回列表-->
<action name="login" class="com.test.ssh.action.UserAction" method="login">
<result name="error">/index.jsp</result>
<result name="userlist" type="redirectAction">getList</result>
</action>
<!-- 修改 返回修改界面 -->
<action name="modify" class="com.test.ssh.action.UserAction" method="modify">
<result name="modify">/jsp/user/modify.jsp</result>
</action>
<!-- 保存 修改和新增 返回列表-->
<action name="save" class="com.test.ssh.action.UserAction" method="save">
<result name="userlist" type="redirectAction">getList</result>
</action>
<!-- 删除 返回列表 -->
<action name="delete" class="com.test.ssh.action.UserAction" method="delete">
<result name="userlist" type="redirectAction">getList</result>
</action>
<!-- 返回列表-->
<action name="getList" class="com.test.ssh.action.UserAction" method="getUserList">
<result name="userlist">/jsp/user/userlist.jsp</result>
</action>
</package>
</struts>
applicationContext.xml 代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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 http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:33068/sshdemo?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC"></property>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.test.ssh.entity.UserEntity</value>
</list>
</property>
</bean>
<!-- 用户 userDao -->
<bean id="userDao" class="com.test.ssh.dao.UserDao">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 用户 userService -->
<bean id="userService" class="com.test.ssh.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
</beans>
七. 配置tomcat,调试
调试效果
八. 问题
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL):
Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
Spring + Hibernate 5 对事务要求更严格,所有读写操作必须通过事务提交;
新增配置applicationContext_tx.xml 配置事务
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--事务管理器-->
<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<aop:config>
<!-- execution(public * *.*.*..*.*(..)) 为自己项目中操作数据库中的方法 -->
<aop:pointcut id="pointcut" expression="execution(* com.test.ssh.service.*.*(..))" />
<aop:advisor pointcut-ref="pointcut" advice-ref="txAdvice" />
</aop:config>
<!-- 配置事务增强 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 配置需要进行事务管理的方法,和事务传播行为 -->
<tx:method name="save*" propagation="REQUIRED" read-only="false"/>
<tx:method name="update*" propagation="REQUIRED" read-only="false"/>
<tx:method name="delete*" propagation="REQUIRED" read-only="false"/>
<tx:method name="insert*" propagation="REQUIRED" read-only="false"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="query*" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>
修改UserService 开启事务
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class UserService {
UserDao userDao;
修改web.xml
<!--配置环境参数,指定Spring配置文件的位置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
/WEB-INF/applicationContext_tx.xml
</param-value>
</context-param>
九. 增加必填字段check
新增文件UserAction-login-validation.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC
"-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<!-- 非字段校验 -->
<validator type="requiredstring">
<param name="fieldName">user.userName</param>
<message>user.userName不能为空</message>
</validator>
<!-- 非字段校验 -->
<validator type="requiredstring">
<param name="fieldName">user.password</param>
<message>user.password不能为空</message>
</validator>
</validators>
修改struts.xml,增加input
<!-- 登录 返回列表-->
<action name="login" class="com.test.ssh.action.UserAction" method="login" >
<result name="error">/index.jsp</result>
<result name="input">/index.jsp</result>
<result name="userlist" type="redirectAction">getList</result>
</action>
参考资料:
struts2教程Struts2验证框架