本文目录导读:

我将为您提供一个完整的SSH(Struts2 + Spring + Hibernate)框架整合案例,这是一个经典的企业级Java Web开发组合。
项目结构
ssh-integration-demo
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ ├── action
│ │ │ │ ├── UserAction.java
│ │ │ │ └── BaseAction.java
│ │ │ ├── service
│ │ │ │ ├── UserService.java
│ │ │ │ └── impl
│ │ │ │ └── UserServiceImpl.java
│ │ │ ├── dao
│ │ │ │ ├── UserDao.java
│ │ │ │ └── impl
│ │ │ │ └── UserDaoImpl.java
│ │ │ ├── entity
│ │ │ │ └── User.java
│ │ │ └── util
│ │ │ └── HibernateUtil.java
│ │ ├── resources
│ │ │ ├── applicationContext.xml
│ │ │ ├── struts.xml
│ │ │ ├── hibernate.cfg.xml
│ │ │ └── log4j.properties
│ │ └── webapp
│ │ ├── WEB-INF
│ │ │ └── web.xml
│ │ ├── index.jsp
│ │ └── jsp
│ │ ├── userList.jsp
│ │ └── addUser.jsp
└── pom.xml
Maven依赖配置 (pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>ssh-integration-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<struts2.version>2.5.30</struts2.version>
<spring.version>5.3.20</spring.version>
<hibernate.version>5.6.10.Final</hibernate.version>
</properties>
<dependencies>
<!-- Struts2 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>${struts2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-spring-plugin</artifactId>
<version>${struts2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-json-plugin</artifactId>
<version>${struts2.version}</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- 其他 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>ssh-demo</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
</project>
实体类 (User.java)
package com.example.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "t_user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", nullable = false, unique = true, length = 50)
private String username;
@Column(name = "password", nullable = false, length = 100)
private String password;
@Column(name = "email", length = 100)
private String email;
@Column(name = "phone", length = 20)
private String phone;
@Column(name = "create_time")
@Temporal(TemporalType.TIMESTAMP)
private Date createTime;
@Column(name = "update_time")
@Temporal(TemporalType.TIMESTAMP)
private Date updateTime;
}
DAO层
UserDao.java
package com.example.dao;
import com.example.entity.User;
import java.util.List;
public interface UserDao {
User findById(Long id);
User findByUsername(String username);
List<User> findAll();
void save(User user);
void update(User user);
void delete(User user);
void deleteById(Long id);
long count();
}
UserDaoImpl.java
package com.example.dao.impl;
import com.example.dao.UserDao;
import com.example.entity.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Repository("userDao")
@Transactional
public class UserDaoImpl implements UserDao {
@Autowired
private SessionFactory sessionFactory;
@Autowired
private HibernateTemplate hibernateTemplate;
private Session getSession() {
return sessionFactory.getCurrentSession();
}
@Override
public User findById(Long id) {
return hibernateTemplate.get(User.class, id);
}
@Override
public User findByUsername(String username) {
Session session = getSession();
Query<User> query = session.createQuery(
"from User where username = :username", User.class);
query.setParameter("username", username);
return query.uniqueResult();
}
@Override
public List<User> findAll() {
return hibernateTemplate.loadAll(User.class);
}
@Override
public void save(User user) {
hibernateTemplate.save(user);
}
@Override
public void update(User user) {
hibernateTemplate.update(user);
}
@Override
public void delete(User user) {
hibernateTemplate.delete(user);
}
@Override
public void deleteById(Long id) {
User user = findById(id);
if (user != null) {
hibernateTemplate.delete(user);
}
}
@Override
public long count() {
Session session = getSession();
Query<Long> query = session.createQuery(
"select count(u) from User u", Long.class);
return query.uniqueResult();
}
}
Service层
UserService.java
package com.example.service;
import com.example.entity.User;
import java.util.List;
public interface UserService {
User findById(Long id);
User findByUsername(String username);
List<User> findAll();
void save(User user);
void update(User user);
void delete(User user);
void deleteById(Long id);
boolean login(String username, String password);
long count();
}
UserServiceImpl.java
package com.example.service.impl;
import com.example.dao.UserDao;
import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
@Transactional(readOnly = true)
public User findById(Long id) {
return userDao.findById(id);
}
@Override
@Transactional(readOnly = true)
public User findByUsername(String username) {
return userDao.findByUsername(username);
}
@Override
@Transactional(readOnly = true)
public List<User> findAll() {
return userDao.findAll();
}
@Override
public void save(User user) {
if (user.getCreateTime() == null) {
user.setCreateTime(new Date());
}
user.setUpdateTime(new Date());
userDao.save(user);
}
@Override
public void update(User user) {
user.setUpdateTime(new Date());
userDao.update(user);
}
@Override
public void delete(User user) {
userDao.delete(user);
}
@Override
public void deleteById(Long id) {
userDao.deleteById(id);
}
@Override
@Transactional(readOnly = true)
public boolean login(String username, String password) {
User user = userDao.findByUsername(username);
return user != null && user.getPassword().equals(password);
}
@Override
@Transactional(readOnly = true)
public long count() {
return userDao.count();
}
}
Action层
BaseAction.java
package com.example.action;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class BaseAction extends ActionSupport
implements ServletRequestAware, ServletResponseAware {
protected HttpServletRequest request;
protected HttpServletResponse response;
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
@Override
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
}
UserAction.java
package com.example.action;
import com.example.entity.User;
import com.example.service.UserService;
import com.opensymphony.xwork2.ActionContext;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Map;
@Data
@EqualsAndHashCode(callSuper = true)
@ParentPackage("struts-default")
@Namespace("/user")
public class UserAction extends BaseAction {
@Autowired
private UserService userService;
private Long id;
private User user;
private List<User> userList;
private String username;
private String password;
@Action(value = "list", results = {
@Result(name = SUCCESS, location = "/jsp/userList.jsp")
})
public String list() {
userList = userService.findAll();
return SUCCESS;
}
@Action(value = "add", results = {
@Result(name = SUCCESS, type = "redirect", location = "/user/list")
})
public String add() {
if (user != null) {
// 检查用户名是否已存在
if (userService.findByUsername(user.getUsername()) != null) {
addActionError("用户名已存在!");
return ERROR;
}
userService.save(user);
addActionMessage("用户添加成功!");
}
return SUCCESS;
}
@Action(value = "edit", results = {
@Result(name = SUCCESS, location = "/jsp/editUser.jsp"),
@Result(name = ERROR, type = "redirect", location = "/user/list")
})
public String edit() {
if (id != null) {
user = userService.findById(id);
if (user == null) {
addActionError("用户不存在!");
return ERROR;
}
}
return SUCCESS;
}
@Action(value = "update", results = {
@Result(name = SUCCESS, type = "redirect", location = "/user/list")
})
public String update() {
if (user != null && user.getId() != null) {
User existingUser = userService.findById(user.getId());
if (existingUser != null) {
existingUser.setEmail(user.getEmail());
existingUser.setPhone(user.getPhone());
if (user.getPassword() != null && !user.getPassword().isEmpty()) {
existingUser.setPassword(user.getPassword());
}
userService.update(existingUser);
addActionMessage("用户更新成功!");
}
}
return SUCCESS;
}
@Action(value = "delete", results = {
@Result(name = SUCCESS, type = "redirect", location = "/user/list")
})
public String delete() {
if (id != null) {
userService.deleteById(id);
addActionMessage("用户删除成功!");
}
return SUCCESS;
}
@Action(value = "login", results = {
@Result(name = SUCCESS, type = "redirect", location = "/user/list"),
@Result(name = "login", location = "/index.jsp")
})
public String login() {
if (username != null && password != null) {
if (userService.login(username, password)) {
ActionContext.getContext().getSession()
.put("currentUser", username);
return SUCCESS;
} else {
addActionError("用户名或密码错误!");
}
}
return "login";
}
@Action(value = "logout", results = {
@Result(name = SUCCESS, type = "redirect", location = "/index.jsp")
})
public String logout() {
Map<String, Object> session = ActionContext.getContext().getSession();
session.remove("currentUser");
return SUCCESS;
}
}
配置文件
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_3_1.xsd"
version="3.1">
<display-name>SSH Integration Demo</display-name>
<!-- 配置Spring监听器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置Struts2过滤器 -->
<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>
<!-- 配置字符编码过滤器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描注解 -->
<context:component-scan base-package="com.example">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 读取数据库配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 配置数据源 (使用C3P0) -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 连接池配置 -->
<property name="minPoolSize" value="5"/>
<property name="maxPoolSize" value="20"/>
<property name="initialPoolSize" value="5"/>
<property name="acquireIncrement" value="5"/>
<property name="maxIdleTime" value="1800"/>
<property name="checkoutTimeout" value="3000"/>
</bean>
<!-- 配置SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>com.example.entity</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.current_session_context_class">
org.springframework.orm.hibernate5.SpringSessionContext
</prop>
</props>
</property>
</bean>
<!-- 配置HibernateTemplate -->
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate5.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="remove*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP切面 -->
<aop:config>
<aop:pointcut id="servicePointcut"
expression="execution(* com.example.service..*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>
</aop:config>
</beans>
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!-- 常量配置 -->
<constant name="struts.devMode" value="true"/>
<constant name="struts.i18n.encoding" value="UTF-8"/>
<constant name="struts.ui.theme" value="simple"/>
<constant name="struts.convention.default.parent.package" value="struts-default"/>
<constant name="struts.convention.package.locators" value="action"/>
<!-- 配置spring集成 -->
<constant name="struts.objectFactory" value="spring"/>
<!-- 配置包 -->
<package name="default" extends="struts-default">
<!-- 配置全局结果 -->
<global-results>
<result name="error">/error.jsp</result>
<result name="input">/error.jsp</result>
</global-results>
<!-- Action配置(也可使用注解方式) -->
<action name="userAction" class="userAction">
<result name="success">/jsp/userList.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
</struts>
db.properties
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/ssh_demo?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 jdbc.username=root jdbc.password=yourpassword
log4j.properties
log4j.rootLogger=INFO, console, file
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=logs/ssh-demo.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# Hibernate日志
log4j.logger.org.hibernate=INFO
log4j.logger.org.hibernate.SQL=DEBUG
log4j.logger.org.hibernate.type=TRACE
# Spring日志
log4j.logger.org.springframework=INFO
JSP页面
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">SSH框架整合示例</title>
<style>
body {
font-family: 'Microsoft YaHei', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
margin: 0;
padding: 0;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.login-box {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
width: 400px;
}
h1 {
text-align: center;
color: #333;
margin-bottom: 30px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
color: #555;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 5px;
box-sizing: border-box;
font-size: 14px;
}
input[type="text"]:focus,
input[type="password"]:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 5px rgba(102,126,234,0.3);
}
.btn-submit {
width: 100%;
padding: 12px;
background: #667eea;
color: white;
border: none;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
transition: background 0.3s;
}
.btn-submit:hover {
background: #5a67d8;
}
.error-message {
color: red;
margin-bottom: 15px;
text-align: center;
}
.message {
color: #28a745;
margin-bottom: 15px;
text-align: center;
}
</style>
</head>
<body>
<div class="login-box">
<h1>SSH整合示例</h1>
<c:if test="${not empty errorMessages}">
<div class="error-message">
<c:forEach items="${errorMessages}" var="error">
${error}<br/>
</c:forEach>
</div>
</c:if>
<c:if test="${not empty actionMessages}">
<div class="message">
<c:forEach items="${actionMessages}" var="msg">
${msg}<br/>
</c:forEach>
</div>
</c:if>
<form action="/user/login" method="post">
<div class="form-group">
<label>用户名</label>
<input type="text" name="username" required/>
</div>
<div class="form-group">
<label>密码</label>
<input type="password" name="password" required/>
</div>
<button type="submit" class="btn-submit">登录</button>
</form>
<div style="text-align: center; margin-top: 20px;">
<a href="/user/list" style="color: #667eea; text-decoration: none;">直接查看用户列表</a>
</div>
</div>
</body>
</html>
userList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">用户列表</title>
<style>
body {
font-family: 'Microsoft YaHei', sans-serif;
background: #f5f6fa;
margin: 0;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 30px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
h1 {
color: #333;
margin: 0;
}
.btn {
padding: 10px 20px;
border-radius: 5px;
text-decoration: none;
color: white;
transition: background 0.3s;
}
.btn-primary {
background: #667eea;
}
.btn-primary:hover {
background: #5a67d8;
}
.btn-danger {
background: #e74c3c;
padding: 5px 10px;
font-size: 12px;
}
.btn-danger:hover {
background: #c0392b;
}
.btn-warning {
background: #f39c12;
padding: 5px 10px;
font-size: 12px;
}
.btn-warning:hover {
background: #d68910;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #e0e0e0;
}
th {
background: #f8f9fa;
color: #333;
font-weight: 600;
}
tr:hover {
background: #f5f6fa;
}
.alert {
padding: 12px;
border-radius: 5px;
margin-bottom: 20px;
}
.alert-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.logout-link {
color: #667eea;
text-decoration: none;
margin-left: 20px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>用户列表</h1>
<div>
<c:if test="${sessionScope.currentUser != null}">
<span>欢迎 <strong>${sessionScope.currentUser}</strong></span>
</c:if>
<a href="/user/add" class="btn btn-primary">添加用户</a>
<a href="/user/logout" class="logout-link">退出</a>
</div>
</div>
<c:if test="${not empty actionMessages}">
<div class="alert alert-success">
<c:forEach items="${actionMessages}" var="msg">
${msg}<br/>
</c:forEach>
</div>
</c:if>
<c:if test="${not empty errorMessages}">
<div class="alert alert-error">
<c:forEach items="${errorMessages}" var="error">
${error}<br/>
</c:forEach>
</div>
</c:if>
<table>
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
<th>电话</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<c:forEach items="${userList}" var="u">
<tr>
<td>${u.id}</td>
<td>${u.username}</td>
<td>${u.email}</td>
<td>${u.phone}</td>
<td><fmt:formatDate value="${u.createTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td><fmt:formatDate value="${u.updateTime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td>
<a href="/user/edit?id=${u.id}" class="btn btn-warning">编辑</a>
<a href="/user/delete?id=${u.id}" class="btn btn-danger"
onclick="return confirm('确定要删除该用户吗?')">删除</a>
</td>
</tr>
</c:forEach>
<c:if test="${empty userList}">
<tr>
<td colspan="7" style="text-align: center; color: #999;">
暂无用户数据
</td>
</tr>
</c:if>
</tbody>
</table>
<div style="margin-top: 20px; color: #666;">
共 ${fn:length(userList)} 条记录
</div>
</div>
</body>
</html>
addUser.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">添加用户</title>
<style>
body {
font-family: 'Microsoft YaHei', sans-serif;
background: #f5f6fa;
margin: 0;
padding: 20px;
}
.container {
max-width: 600px;
margin: 0 auto;
background: white;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 30px;
}
h1 {
color: #333;
margin-bottom: 30px;
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播