单一架构案例
- 一、创建工程,引入依赖
- 二、搭建环境:持久化层
- 三、搭建环境:事务控制
- 四、搭建环境:表示层
- 五、搭建环境:辅助功能
- 六、业务功能:登录
- 七、业务功能:显示列表
- 八、业务功能:显示详情
- 九、业务功能:回复
- 十、业务功能:登录检查
- 十一、打包部署
本章节将以创建一个单一架构的业务系统,从搭建到部署的过程,演示Maven项目
一、创建工程,引入依赖
1.架构
①架构的概念
架构其实就是项目的结构,只是因为架构是一个更大的词,通常来形容比较大规模事物的结构。
②单一架构
单一架构也叫all-in-one的结构,就是所有的代码、配置文件、各种资源都在同一个工程
- 一个项目包含一个工程
- 导出一个war包
- 放在一个Tomcat上运行
2.创建工程
3. 引入依赖
①搜索依赖信息的网站
【1】 到哪找?
依赖信息网站
【2】怎么选择?
- 确定技术选型:确定我们项目中要使用哪些技术
- 到网站去搜索具体技术的依赖信息
- 确定这个技术使用哪个版本的依赖
- 考虑因素1:看是否有别的技术要求这里必须使用某一个版本
- 考虑因素2:如果没有硬性要求,那么选择较高版本或者下载量的版本
- 在实际使用中检验所有依赖信息是否都正常可用
tips:
确定技术选型、组件依赖列表,项目划分模块等操作都是属于架构设计的范围。
- 项目本身所属行业的基本特点
- 项目具体的功能需求
- 项目预计访问压力程度
- 项目预计将来需要扩展的功能
②持久化层所需依赖
首先确保自己本机已经安装了mysql数据库,安装过程不再赘述。
mysql依赖
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
druid依赖
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
③表示层所需依赖
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
④辅助功能所需依赖
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
⑤最终完整依赖信息
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
4.建包
package功能 | package名称 |
---|---|
主包 | com.sr.maven |
子包【实体类】 | com.sr.maven.entity |
子包 【servlet基类包】 | com.sr.maven.servlet.base |
子包 【servelet模块包】 | com.sr.maven.servlet.module |
子包 【servlet接口包】 | com.sr.maven.servlet.api |
子包 【servlet实现类包】 | com.sr.maven.servlet.imp |
子包 【Dao接口包】 | com.sr.maven.dao.api |
子包 【Dao实现类包】 | com.sr.maven.dao.imp |
子包【Filter过滤器包】 | com.sr.maven.filter |
子包 【异常类包】 | com.sr.maven.exception |
子包 【工具类包】 | com.sr.maven.util |
子包 【测试类包】 | com.sr.maven.test |
二、搭建环境:持久化层
1.数据建模
①物理建模
在mysql数据库运行sql语句,进行物理建模,建表
CREATE DATABASE db_imperial_court;
USE db_imperial_court;
CREATE TABLE t_emp (
emp_id INT PRIMARY KEY auto_increment,
emp_name CHAR ( 100 ) NOT NULL,
emp_position CHAR ( 100 ) NOT NULL,
login_account CHAR ( 100 ) NOT NULL UNIQUE,
login_password CHAR ( 100 ) NOT NULL
);
INSERT INTO t_emp ( emp_name, emp_position, login_account, login_password )
VALUES# 16540504
( '爱新觉罗.玄烨', 'emperor', 'xiaoxuanzi1654', '25325c896624D444B2E241807DCAC988' ),
( '纳兰明珠', 'minister', 'brightba771635', '25325c896624D444B2E241807DCAC988' ),
( '赫舍里.索额图', 'minister', 'tutu1636', '25325c896624D444B2E241807DCAC988' );
CREATE TABLE t_memorials (
memorials_id INT PRIMARY KEY auto_increment,
memorials_title CHAR ( 100 ) NOT NULL,
memorials_content VARCHAR ( 5000 ) NOT NULL,
memorials_emp INT NOT NULL,
memorials_create_time CHAR ( 100 ),
feedback_time CHAR ( 100 ),
feedback_content VARCHAR ( 1000 ),
memorials_status INT NOT NULL
);
INSERT INTO t_memorials ( memorials_title, memorials_content, memorials_emp, memorials_create_time, feedback_time, feedback_content, memorials_status )
VALUES# 16540504
( '浙江巡抚奏钱塘江堤决口疏', '皇上啊,不好了!钱塘江发大水啦!堤坝冲毁啦!您看咋弄啊!', 2, '1690-05-07', NULL, NULL, 0 ),
( '左都御史参鳌拜圈地口疏', '皇上啊,鳌拜这厮不是东西啊!占老百姓的地呀,还打人呀!您看咋弄啊', 3, '1690-04-14', NULL, NULL, 0 ),
( '督察员参吴三桂不臣疏', '皇上啊,不好了!吴三桂那孙子想造反!', 2, '1693-11-18', NULL, NULL, 0 ),
( '兵部奏准噶尔犯境疏', '皇上啊,不好了!噶尔丹要打过来了!', 3, '1693-11-18', NULL, NULL, 0 );
②逻辑建模
【1】Emp实体类
package com.sr.maven.entity;
public class Emp {
private Integer empId;
private String empName;
private String empPosition;
private String loginAccount;
private String loginPassword;
public Emp() {
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getEmpPosition() {
return empPosition;
}
public void setEmpPosition(String empPosition) {
this.empPosition = empPosition;
}
public String getLoginAccount() {
return loginAccount;
}
public void setLoginAccount(String loginAccount) {
this.loginAccount = loginAccount;
}
public String getLoginPassword() {
return loginPassword;
}
public void setLoginPassword(String loginPassword) {
this.loginPassword = loginPassword;
}
}
【2】Memorials实体类
public class Memorials {
private Integer memorialsId;
private String memorialsTitle;
private String memorialsContent;
private String memorialsContentDigest;
private Integer memorialsEmp;
private String memorialsEmpEmpName;
private String memorialsCreateTime;
private String feedbackTime;
private String feedbackContent;
private Integer memorialsStatus;
public Memorials() {
}
public Integer getMemorialsId() {
return memorialsId;
}
public void setMemorialsId(Integer memorialsId) {
this.memorialsId = memorialsId;
}
public String getMemorialsTitle() {
return memorialsTitle;
}
public void setMemorialsTitle(String memorialsTitle) {
this.memorialsTitle = memorialsTitle;
}
public String getMemorialsContent() {
return memorialsContent;
}
public void setMemorialsContent(String memorialsContent) {
this.memorialsContent = memorialsContent;
}
public String getMemorialsContentDigest() {
return memorialsContentDigest;
}
public void setMemorialsContentDigest(String memorialsContentDigest) {
this.memorialsContentDigest = memorialsContentDigest;
}
public Integer getMemorialsEmp() {
return memorialsEmp;
}
public void setMemorialsEmp(Integer memorialsEmp) {
this.memorialsEmp = memorialsEmp;
}
public String getMemorialsEmpEmpName() {
return memorialsEmpEmpName;
}
public void setMemorialsEmpEmpName(String memorialsEmpEmpName) {
this.memorialsEmpEmpName = memorialsEmpEmpName;
}
public String getMemorialsCreateTime() {
return memorialsCreateTime;
}
public void setMemorialsCreateTime(String memorialsCreateTime) {
this.memorialsCreateTime = memorialsCreateTime;
}
public String getFeedbackTime() {
return feedbackTime;
}
public void setFeedbackTime(String feedbackTime) {
this.feedbackTime = feedbackTime;
}
public String getFeedbackContent() {
return feedbackContent;
}
public void setFeedbackContent(String feedbackContent) {
this.feedbackContent = feedbackContent;
}
public Integer getMemorialsStatus() {
return memorialsStatus;
}
public void setMemorialsStatus(Integer memorialsStatus) {
this.memorialsStatus = memorialsStatus;
}
}
2.数据库连接信息
编写自己的数据库配置
driverClassName=com.mysql.cj.jdbc.Driver
url= jdbc:mysql://localhost:3306/db_imperial_court?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username=自己的账户
password=自己的密码
initialSize=10
maxActive=20
maxWait=10000
3.获取数据库连接
①创建JDBCUtils工具类
首先先放出完整的工具类内容,下面进行分步骤的添加解释
package com.sr.maven.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
/**
* 功能1:从数据源获取数据库链接
* 功能2:将数据源获取到数据库连接绑定到本地线程 ThreadLocal
* 功能3:释放线程时和本地超线程解除绑定
*/
public class JDBCUtils {
//数据源成员变量,设置为静态资源,保证大对象的单例性,同时保证静态方法中可以访问
private static DataSource dataSource;
//由于ThreadLocal对象需要作为绑定数据时K-v对中的key,所以需要保证唯一性
//加static声明为静态资源可保证唯一性
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
//在静态代码块中初始化数据源
static {
try {
//从jdbc.properties中读取链接数据库的信息
//为了保证程序代码的可移植性,需要基于一个确定的基准来读取这个文件
//确定的基准,类路径的根目录,resource目录下的内容经过构建后打包操作会确定放在 WEB-INF/classes目录下。
//WEB-INF/classes 目录存放编译好的*.class字节码文件,所以这个目录我们就称之为类路径
//类路径无论是在本地运行还是在服务器端运行都是一个确定的路径
//具体操作代码
//1.获取当前类的类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
//2.通过类加载器对象从类路径根目录下读取文件
InputStream stream = classLoader.getResourceAsStream("jdbc.properties");
//3.使用Properties类封装属性文件中的数据
Properties properties = new Properties();
properties.load(stream);
//4.根据Properties对象(已经封装了数据库连接信息)来创建数据源对象
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
//为了避免在真正抛出异常后,catch块捕捉获取到异常掩盖问题
//这里将所捕获的异常封装为运行时异常继续抛出去
throw new RuntimeException(e);
}
}
public static Connection getConnection() {
Connection connection;
try {
//1.尝试从当前线程检查是否已存在绑定的Connection对象
connection = threadLocal.get();
//2.检查Connection对象是否为null
if (connection == null) {
connection = dataSource.getConnection();
//绑定到当前线程
threadLocal.set(connection);
}
}catch (SQLException e){
e.printStackTrace();
throw new RuntimeException(e);
}
return connection;
}
public static void releaseConnection(Connection connection){
if(connection!=null){
try {
connection.close();
threadLocal.remove();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
}
②创建javax.sql.DataSource对象
//数据源成员变量,设置为静态资源,保证大对象的单例性,同时保证静态方法中可以访问
private static DataSource dataSource;
//在静态代码块中初始化数据源
static {
try {
//从jdbc.properties中读取链接数据库的信息
//为了保证程序代码的可移植性,需要基于一个确定的基准来读取这个文件
//确定的基准,类路径的根目录,resource目录下的内容经过构建后打包操作会确定放在 WEB-INF/classes目录下。
//WEB-INF/classes 目录存放编译好的*.class字节码文件,所以这个目录我们就称之为类路径
//类路径无论是在本地运行还是在服务器端运行都是一个确定的路径
//具体操作代码
//1.获取当前类的类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
//2.通过类加载器对象从类路径根目录下读取文件
InputStream stream = classLoader.getResourceAsStream("jdbc.properties");
//3.使用Properties类封装属性文件中的数据
Properties properties = new Properties();
properties.load(stream);
//4.根据Properties对象(已经封装了数据库连接信息)来创建数据源对象
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
//为了避免在真正抛出异常后,catch块捕捉获取到异常掩盖问题
//这里将所捕获的异常封装为运行时异常继续抛出去
throw new RuntimeException(e);
}
}
③创建ThreadLocal对象
【1】提出需求
(1)在一个方法内控制事务
如果在每一个Service方法中都写下面的代码,那么代码重复性就太高了
try{
//1.获取数据连接
//重要:要保证参与事务的多个数据库操作(SQL语句)使用的是同一个数据库连接
Connection conn = JDBCUtils.getConnection();
//2.核心操作
//....省略
//3.核心操作陈工结束,可以提交事务
conn.commit();
}catch(Exception e){
//4 核心操作抛出异常,必须回滚事务
conn.rollback();
}finally{
//5.释放数据库连接
JDBCUtils.releaseConnection(conn);
}
(2)将重复的代码抽取到Filter中
所谓当前请求覆盖的Servlet方法、Service方法、Dao方法就是chain.doFilter间接调用的方法。
public void doFilter(ServletRequest request,ServlertResponse response ,FilterChain chain){
try{
//1.获取数据连接
//重要:要保证参与事务的多个数据库操作(SQL语句)使用的是同一个数据库连接
Connection conn = JDBCUtils.getConnection();
//关闭自动提交
connection.setAutoCommit(false);
//2.核心操作:通过chain对象放行当前请求
//这样就可以保证当前请求覆盖的Servlet方法、Service方法、Dao方法都在同一个事务中
//同时各个请求都经过这个Filter,所以当前事务控制的代码这里只写了一遍
//避免了代码的冗余
chain.doFilter(request,response);
//3.核心操作陈工结束,可以提交事务
conn.commit();
}catch(Exception e){
//4 核心操作抛出异常,必须回滚事务
conn.rollback();
}finally{
//5.释放数据库连接
JDBCUtils.releaseConnection(conn);
}
}
(3)数据的跨方法传递
但是,通过(2),我们还是会遇到一个难题,如图所示,为了保证使用同一个数据库连接对象,但是chain.doFilter方法又无法传参,我们该怎么办?
通过JDBCUtils工具类获取的Connection对象需要传递给Dao方法,让事务涉及到的所有Dao方法用的都是同一个Connection对象。
但是Connection对象无法通过chain.doFilter()方法以参数的形式传递。以下所有方法调用都是在同一线程内。
【2】ThreadLocal对象的功能
- 全类名:java.lang.ThreadLocal
- 泛型T:要绑定到当前线程的类型
- 三个主要的方法
方法名 | 功能 |
---|---|
set(T value) | 将数据绑定到当前线程 |
get() | 从当前线程获取已绑定的数据 |
remove | 将数据从当前线程移除 |
【3】Java代码
//由于ThreadLocal对象需要作为绑定数据时K-v对中的key,所以需要保证唯一性
//加static声明为静态资源可保证唯一性
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
④声明方法:获取数据库连接
public static Connection getConnection() {
Connection connection;
try {
//1.尝试从当前线程检查是否已存在绑定的Connection对象
connection = threadLocal.get();
//2.检查Connection对象是否为null
if (connection == null) {
connection = dataSource.getConnection();
//绑定到当前线程
threadLocal.set(connection);
}
}catch (SQLException e){
e.printStackTrace();
throw new RuntimeException(e);
}
return connection;
}
⑤声明方法:释放数据库连接
public void releaseConnection(Connection connection){
if(connection!=null){
try {
connection.close();
threadLocal.remove();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
⑥初步测试
我们创建一个测试类,看能否正常获取到连接,如下图所示,结果显示正常。
public class ImperialCourtTest {
@Test
public void testGetConnection(){
Connection connection = JDBCUtils.getConnection();
System.out.println("connection = "+connection);
JDBCUtils.releaseConnection(connection);
}
}
4.BaseDao
①泛型的说明
/**
* BaseDao类:所有Dao类实现类的基类
* @param <T> 实体类的类型
*/
public class BaseDao<T> {
//DBUtils 工具包提供的数据操作对象
private QueryRunner runner = new QueryRunner();
/**
* 查询单个对象
* @param sql sql语句
* @param entityBean 实体类对象
* @param parameters 传给sql语句的参数
* @return 查询到的实体类对象
*/
public T getSingleBean(String sql ,Class<T> entityBean,Object ... parameters){
//获取数据库连接
Connection connection = JDBCUtils.getConnection();
try {
return runner.query(connection,sql,new BeanHandler<>(entityBean),parameters);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
/**
* 查询多个对象
* @param sql sql语句
* @param entityBean 实体类对象
* @param parameters 传给sql语句的参数
* @return 查询到的实体类对象
*/
public List<T> getBeanList(String sql , Class<T> entityBean, Object ... parameters){
//获取数据库连接
Connection connection = JDBCUtils.getConnection();
try {
return runner.query(connection,sql,new BeanListHandler<>(entityBean),parameters);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public int update (String sql ,Object ... parameters){
try{
Connection connection = JDBCUtils.getConnection();
return runner.update(connection,sql,parameters);
}catch (SQLException e){
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
②测试BaseDao
运行显示,结果正常。
public class ImperialCourtTest {
private BaseDao<Emp> baseDao = new BaseDao<>();
@Test
public void testGetConnection(){
Connection connection = JDBCUtils.getConnection();
System.out.println("connection = "+connection);
JDBCUtils.releaseConnection(connection);
}
@Test
public void testGetSingleBean(){
String sql = "select emp_id empId,emp_name empName,emp_position empPosition,login_account loginAccount,login_password loginPassword from t_emp where emp_id = ?";
Emp singleBean = baseDao.getSingleBean(sql, Emp.class, 1);
System.out.println(singleBean);
}
@Test
public void testGeteBeanList(){
String sql = "select emp_id empId,emp_name empName,emp_position empPosition,login_account loginAccount,login_password loginPassword from t_emp ";
List<Emp> beanList = baseDao.getBeanList(sql, Emp.class);
beanList.forEach(i->
System.out.println(i.toString())
);
}
@Test
public void testUpdate(){
String sql = "update t_emp set emp_position = ? where emp_id = ?";
String empPosition = "emperor";
String empId = "3";
int affectRow = baseDao.update(sql,empPosition,empId);
System.out.println("affectRow = "+affectRow);
}
}
5.子类Dao
①创建接口和实现类
EmpDao
public interface EmpDao {
}
EmpDaoImpl
public class EmpDaoImpl extends BaseDao<Emp> implements EmpDao {
}
MemorialsDao
public interface MemorialsDao {
}
MemorialsDaoImpl
public class MemorialsDaoImpl extends BaseDao<Memorials> implements MemorialsDao {
}
三、搭建环境:事务控制
1.总体思路
按照先前操作的代码和思路,总结如下:
2.TransactionFilter
①创建Filter类
②完整代码
package com.sr.maven.filter;
import com.sr.maven.util.JDBCUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
public class TransactionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
//声明一个集合保存静态资源扩展名,非操作sql的 请求进入到这个过滤器 会浪费性能
private static Set<String> staticResourceExNameSet;
static {
staticResourceExNameSet = new HashSet<>();
staticResourceExNameSet.add(".png");
staticResourceExNameSet.add(".jpg");
staticResourceExNameSet.add(".js");
staticResourceExNameSet.add(".css");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//前置操作,排除静态资源
HttpServletRequest request = (HttpServletRequest)servletRequest;
String servletPath = request.getServletPath();
if(servletPath.contains(".")){
String extName = servletPath.substring(servletPath.lastIndexOf("."));
if(staticResourceExNameSet.contains(extName)){
//如果检测到当前请求确实是静态资源,则直接方形,不做事务操作
filterChain.doFilter(servletRequest,servletResponse);
return;
}
}
//1.获取数据库连接
Connection connection =null;
//
try {
connection = JDBCUtils.getConnection();
//关闭自动提交
connection.setAutoCommit(false);
//2.核心操作
filterChain.doFilter(servletRequest,servletResponse);
//3.提交事务
connection.commit();
}catch (Exception e){
try {
//4.回滚事务
assert connection != null;
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
//页面显示:将这里捕获到的异常发送到指定页面
String message = e.getMessage();
request.setAttribute("message",message);
request.getRequestDispatcher("/").forward(request,servletResponse);
}
finally {
JDBCUtils.releaseConnection(connection);
}
}
@Override
public void destroy() {
}
}
③配置web.xml
web.xml中增加过滤器配置
<filter>
<filter-name>txFilter</filter-name>
<filter-class>com.sr.maven.filter.TransactionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>txFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
④注意点
【1】确保异常回滚
在程序执行的过程中,必须让所有的catch块把编译时异常转成运行时异常抛出,否则,Filter捕获不到就无法回滚。
【2】谨防数据库连接提前释放
由于诸多操作都是在使用同一个数据库连接,中间任何一个环节释放数据库连接都会导致后续操作无法正常完成。
四、搭建环境:表示层
1.视图模板技术Thymeleaf
①服务器端渲染
②简要的工作机制
【1】初始化阶段
- 目标:创建TemplateEngine对象
- 封装:因为对每一个请求来说,TemplateEngine对象使用的都是同一个,所以在初始化阶段准备好。
【2】请求处理阶段
③逻辑视图与物理视图
假设有如下页面地址:
/WEB-INF/pages/apple.html
/WEB-INF/pages/banana.html
/WEB-INF/pages/orange.html
/WEB-INF/pages/grape.html
/WEB-INF/pages/egg.html
这样的地址可以直接访问到页面本身,我们称之为:物理视图。而将物理视图中前面,后面的固定内容抽取出来,让每次请求指定中间变化部分即可,那么中间变化部分就叫:逻辑视图。
④ViewBaseServlet完整代码
为了简化视图页面的处理过程,封装一个基类,以后具体业务直接继承就好。
package com.sr.maven.servlet.base;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ViewBaseServlet extends HttpServlet {
private TemplateEngine templateEngine;
@Override
public void init() throws ServletException {
//1.获取ServletContext对象
ServletContext servletContext = this.getServletContext();
//2.创建Thymeleaf解析器对象
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
//给解析器对象设置参数
templateResolver.setTemplateMode(TemplateMode.HTML);
//设置前缀
String viewPrefix = servletContext.getInitParameter("view-prefix");
templateResolver.setPrefix(viewPrefix);
//设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");
templateResolver.setSuffix(viewSuffix);
//设置缓存过期时间
templateResolver.setCacheTTLMs(600000L);
templateResolver.setCacheable(true);
//设置服务器编码格式
templateResolver.setCharacterEncoding("utf-8");
//创建模板引擎对象
templateEngine = new TemplateEngine();
//给模板引擎设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
public void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse res) throws IOException {
//1.设置响应体内容类型和字符集
res.setContentType("text/html;charset=UTF-8");
//2.创建WebContext对象
WebContext webContext = new WebContext(req,res,getServletContext());
//3.处理模板数据
templateEngine.process(templateName,webContext,res.getWriter());
}
}
⑤增加前缀后缀的web.xml配置
<context-param>
<param-name>view-prefix</param-name>
<param-value>/WEB-INF/pages/</param-value>
</context-param>
<context-param>
<param-name>view-suffix</param-name>
<param-value>.html/</param-value>
</context-param>
⑥Thymeleaf页面语法
详细去看官网文档就可以
2.ModelBaseServlet
①提出问题
【1】我们的需求
【2】HttpServlet的局限
- doGet()方法:处理Get请求
- doPost()方法:处理Post请求
②解决方案
- 每个请求附带一个请求参数,表明自己要调用的目标方法
- Servlet根据目标方法通过反射调用目标方法
③完整代码
package com.sr.maven.servlet.base;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
public class ModelBaseServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.在所有的request.getParameter()前面设置解析请求体的字符集
req.setCharacterEncoding("UTF-8");
//2.从请求参数中获取method对应的数据
String method = req.getParameter("method");
//3。通过反射调用method对应的方法
//这里使用this. 是获取的子类的类型,因为真正执行的时候 是走的子类
Class<? extends ModelBaseServlet> clazz = this.getClass();
try{
//获取method对应的Method对象
Method methodObject = clazz.getDeclaredMethod(method,HttpServletRequest.class,HttpServletResponse.class);
//打开访问权限
methodObject.setAccessible(true);
//通过method调用方法
methodObject.invoke(this,req,resp);
}catch (Exception e){
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
④继承关系
五、搭建环境:辅助功能
1.常量类
package com.sr.maven.util;
public class ImperialCourtConst {
private static final String LOGIN_FAIL_MESSAGE = "帐号、密码错误,不可进宫!";
private static final String ACCESS_DENIED_MESSAGE = "宫闱禁地,不可擅入!";
}
2.MD5加密工具类
package com.sr.maven.util;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Util {
public static String encode(String source) {
//1.判断明文字符串是否有效
if (source == null || "".equals(source)) {
throw new RuntimeException("用于加密的明文不可为空");
}
//2.声明算法名称
String algorithm = "md5";
//3.获取MessageDigest对象
MessageDigest messageDigest = null;
try {
messageDigest = MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//4. 获取明文字符串对应的字节数组
byte[] input = source.getBytes();
//5.执行加密
byte[] output = messageDigest.digest(input);
//6.创建BigInter对象
int signum =1 ;
BigInteger bigInteger = new BigInteger(signum,output);
//7.按照16进制将BigInteger的值转换为字符串
int radix = 16;
return bigInteger.toString(radix).toUpperCase();
}
}
3.日志配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="true">
<!--指定日志输出位置-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--日志输出的格式-->
<!--按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行-->
<pattern>[%d{HH:mm:ss.SSS}][%-5level][%thread][%logger][%msg]%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!--设置全局日志级别,日志级别按照顺序分别是:DEBUG,INFO、WARN、ERROR-->
<!--指定任何一个日志级别都只打印当前级别日志和后面级别的日志-->
<root level = "INFO">
<!--指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender-->
<appender-ref ref="STDOUT"/>
</root>
<!--专门给一个包指定日志级别-->
<logger name="com.sr" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
</configuration>
六、业务功能:登录
1.显示首页
① 流程图
②创建PortalServlet
【1】创建Java类
package com.sr.maven.servlet.module;
import com.sr.maven.servlet.base.ViewBaseServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class PortalServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//声明要访问的首页的逻辑视图
String templateName = "index";
//调用父类的方法根据逻辑视图名称渲染视图
processTemplate(templateName,req,resp);
}
}
【2】注册,添加到web.xml中
<servlet>
<servlet-name>portalServlet</servlet-name>
<servlet-class>com.sr.maven.servlet.module.PortalServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>portalServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
③在index.html中编写登录页面
<!DOCTYPE html>
<html lang="en" xml:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>乾清宫</title>
</head>
<body>
<!--@{/auth}解析后:demo/auth ,获取项目的contextPath-->
<form th:action="@{auth}" method="post">
<!--传递method请求参数,目的是为了让当前请求调用AuthServlet的login方法-->
<input type="hidden" name="method" value="login"/>
<!--th:text解析表达式会替换标签体-->
<!--${attrName}从请求域获取属性名为attrName的属性值-->
<p th:text="${message}"></p>
<p th:text="${systemMessage}"></p>
帐号:<input type="text" name="loginAccount"/><br/>
帐号:<input type="password" name="loginPassword"/><br/>
<button type="submit">进宫</button>
</form>
</body>
</html>
2.登录操作
①流程图
②编写EmpDao的方法
package com.sr.maven.dao.api;
import com.sr.maven.entity.Emp;
public interface EmpDao {
Emp selectEmpByLoginAccount(String loginAccount, String loginPassword);
}
package com.sr.maven.dao.impl;
import com.sr.maven.dao.BaseDao;
import com.sr.maven.dao.api.EmpDao;
import com.sr.maven.entity.Emp;
public class EmpDaoImpl extends BaseDao<Emp> implements EmpDao {
@Override
public Emp selectEmpByLoginAccount(String loginAccount, String loginPassword) {
//1.编写sql语句
String sql = "select emp_id empId,emp_name empName,emp_position empPosition,login_account loginAccount,login_password loginPassword from t_emp where login_account=? and login_password=?";
//2.调用父类方法查询单个对象
return super.getSingleBean(sql, Emp.class, loginAccount,loginPassword);
}
}
③创建EmpService类
package com.sr.maven.service;
import com.sr.maven.entity.Emp;
public interface EmpService {
Emp getEmpByLoginAccount(String loginAccount, String loginPassword);
}
package com.sr.maven.service.impl;
import com.sr.maven.dao.api.EmpDao;
import com.sr.maven.dao.impl.EmpDaoImpl;
import com.sr.maven.entity.Emp;
import com.sr.maven.exception.LoginFailException;
import com.sr.maven.service.EmpService;
import com.sr.maven.util.ImperialCourtConst;
import com.sr.maven.util.MD5Util;
public class EmpServiceImpl implements EmpService {
private EmpDao empDao = new EmpDaoImpl();
@Override
public Emp getEmpByLoginAccount(String loginAccount, String loginPassword) {
//1.对密码进行加密
String encodeLoginPassword = MD5Util.encode(loginPassword);
//2.根据账户和密码加密密码查询数据库
Emp emp = empDao.selectEmpByLoginAccount(loginAccount,loginPassword);
//3.检查Emp对象是否为空
if(emp !=null ){
// ①不为null,返回emp
return emp;
}else
{
//抛出登录异常失败
throw new LoginFailException(ImperialCourtConst.LOGIN_FAIL_MESSAGE);
}
}
}
④创建登录失败异常
package com.sr.maven.exception;
public class LoginFailException extends RuntimeException{
public LoginFailException() {
super();
}
public LoginFailException(String message) {
super(message);
}
public LoginFailException(String message, Throwable cause) {
super(message, cause);
}
public LoginFailException(Throwable cause) {
super(cause);
}
protected LoginFailException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
⑤增加一个常量
⑥创建AuthServlet类
package com.sr.maven.servlet.module;
import com.sr.maven.entity.Emp;
import com.sr.maven.exception.LoginFailException;
import com.sr.maven.service.EmpService;
import com.sr.maven.service.impl.EmpServiceImpl;
import com.sr.maven.servlet.base.ModelBaseServlet;
import com.sr.maven.util.ImperialCourtConst;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class AuthServlet extends ModelBaseServlet {
private EmpService empService = new EmpServiceImpl();
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
//1.先获取请求参数
String loginAccount = req.getParameter("loginAccount");
String loginPassword = req.getParameter("loginPassword");
//2.调用EmpService 的方法,执行登录的逻辑
Emp emp = empService.getEmpByLoginAccount(loginAccount,loginPassword);
//3. 通过requet获取HTTPSession
HttpSession session = req.getSession();
//4.将查询的Emp对象存入Session域
session.setAttribute(ImperialCourtConst.LOGIN_EMP_ATTR_NAME,emp);
//5.前往指定的页面视图
String templateName = "temp";
processTemplate(templateName,req,resp);
}catch (Exception e){
e.printStackTrace();
//判断此处是否是 登录失败异常
if(e instanceof LoginFailException){
//如果是登录失败异常跳转回登录页面
//存入请求域
req.setAttribute("message",e.getMessage());
//处理视图:index
processTemplate("index",req,resp);
}else{
//如果不是登录异常则封装为运行时异常继续抛出
throw new RuntimeException(e);
}
}
}
}
⑦temp页面
<!DOCTYPE html>
<html lang="en" xml:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>temp</title>
</head>
<body>
<p th:text="${session.loginInfo}"></p>
</body>
</html>
⑧注册,在web.xml中增加信息
<servlet>
<servlet-name>authServlet</servlet-name>
<servlet-class>com.sr.maven.servlet.module.AuthServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>authServlet</servlet-name>
<url-pattern>/auth</url-pattern>
</servlet-mapping>
⑨运行结果
帐号密码: xiaoxuanzi1654 16540504
3.退出登录
①在临时页面编写超链接
当前完整代码
<!DOCTYPE html>
<html lang="en" xml:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>temp</title>
</head>
<body>
<p th:text="${session.loginInfo}"></p>
<a th:href="@{/auth?method=logout}">退朝</a>
</body>
</html>
②在AuthServlet编写退出的逻辑
protected void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.通过request 对象获取 HttpSession对象
HttpSession session = req.getSession();
//2.将HttpSession设置失效
session.invalidate();
//3.回到index页面
processTemplate("index",req,resp);
}
}
七、业务功能:显示列表
1.流程图
2.创建组件
①创建Java类
package com.sr.maven.servlet.module;
import com.sr.maven.entity.Memorials;
import com.sr.maven.service.MemorialsService;
import com.sr.maven.service.impl.MemorialsServiceImpl;
import com.sr.maven.servlet.base.ModelBaseServlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
public class WorkServlet extends ModelBaseServlet {
private MemorialsService memorialsService = new MemorialsServiceImpl();
protected void showMemorialsDigestList(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//. 1.调用Service方法查询数据
List<Memorials> list = memorialsService.getAllMemorialsDigest();
//将查询到的数据存入请求域
String templateName = "memorials-list";
processTemplate(templateName,req,resp);
}
}
package com.sr.maven.service;
import com.sr.maven.entity.Memorials;
import java.util.List;
public interface MemorialsService {
List<Memorials> getAllMemorialsDigest();
}
package com.sr.maven.service.impl;
import com.sr.maven.dao.api.MemorialsDao;
import com.sr.maven.dao.impl.MemorialsDaoImpl;
import com.sr.maven.entity.Memorials;
import com.sr.maven.service.MemorialsService;
import java.util.List;
public class MemorialsServiceImpl implements MemorialsService {
private MemorialsDao memorialsDao = new MemorialsDaoImpl();
@Override
public List<Memorials> getAllMemorialsDigest() {
return memorialsDao.selectAllMemorialsDigest();
}
}
package com.sr.maven.dao.api;
import com.sr.maven.entity.Memorials;
import java.util.List;
public interface MemorialsDao {
List<Memorials> selectAllMemorialsDigest();
}
package com.sr.maven.dao.impl;
import com.sr.maven.dao.BaseDao;
import com.sr.maven.dao.api.MemorialsDao;
import com.sr.maven.entity.Memorials;
import java.util.List;
public class MemorialsDaoImpl extends BaseDao<Memorials> implements MemorialsDao {
@Override
public List<Memorials> selectAllMemorialsDigest() {
String sql = "SELECT\n" +
"\tmemorials_id memorialsId,\n" +
"\tmemorials_title memorialsTitle,\n" +
"\tconcat(left(memorials_content,10),'...') as memorialsContentDigest,\n" +
"\tmemorials_content as memorialsContent,\n" +
"\tmemorials_emp as memorialsEmp,\n" +
"\temp_name as memorialsEmpEmpName,\n" +
"\tmemorials_create_time as memorialsCreateTime,\n" +
"\tfeedback_time as feedbackTime,\n" +
"\tfeedback_content as feedbackContent,\n" +
"\tmemorials_status as memorialsStatus\n" +
"FROM\n" +
"\tt_memorials m\n" +
"\tleft join t_emp e on m.memorials_emp=e.emp_id";
return super.getBeanList(sql,Memorials.class);
}
}
② 注册,在web.xml中增加信息
<servlet>
<servlet-name>workServlet</servlet-name>
<servlet-class>com.sr.maven.servlet.module.WorkServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>workServlet</servlet-name>
<url-pattern>/work</url-pattern>
</servlet-mapping>
3.页面显示
<!DOCTYPE html>
<html lang="en" xml:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>temp</title>
<style type="text/css">
table{
border-collapse: collapse;
margin: 0px auto 0px auto;
}
table th ,td{
border: 1px solid black;
text-align: center;
}
div{
text-align: right;
}
</style>
</head>
<body>
<!--登录信息部分-->
<div>
<span th:if="${session.loginInfo.empPosition == 'emperor'}">恭请皇上圣安</span>
<span th:if="${session.loginInfo.empPosition == 'minister'}">给<span th:text="${session.loginInfo.empName}"></span>大人请安</span>
<a th:href="@{/auth?method=logout}">退朝</a>
</div>
<!--数据显示部分-->
<table>
<thead>
<th>奏折标题</th>
<th>内容摘要</th>
<th>上疏大臣</th>
<th>上疏时间</th>
<th>奏折状态</th>
<th>奏折详情</th>
</thead>
<tbody th:if="${#lists.isEmpty(memorialsList)}">
<tr>
<td colspan="6">没有人上过折子</td>
</tr>
</tbody>
<tbody th:if="${not #lists.isEmpty(memorialsList)}">
<tr th:each="memorials : ${memorialsList}">
<td th:switch="${memorials.memorialsStatus}">
<span th:text="${memorials.memorialsTitle}" th:case="0" style="color: red">奏折标题</span>
<span th:text="${memorials.memorialsTitle}" th:case="1" style="color: blue">奏折标题</span>
<span th:text="${memorials.memorialsTitle}" th:case="2" >奏折标题</span>
</td>
<td th:switch="${memorials.memorialsStatus}">
<span th:text="${memorials.memorialsContentDigest}" th:case="0" style="color: red">内容摘要</span>
<span th:text="${memorials.memorialsContentDigest}" th:case="1" style="color: blue">内容摘要</span>
<span th:text="${memorials.memorialsContentDigest}" th:case="2" >内容摘要</span>
</td>
<td th:switch="${memorials.memorialsStatus}">
<span th:text="${memorials.memorialsEmpEmpName}" th:case="0" style="color: red">上疏大臣</span>
<span th:text="${memorials.memorialsEmpEmpName}" th:case="1" style="color: blue">上疏大臣</span>
<span th:text="${memorials.memorialsEmpEmpName}" th:case="2" >上疏大臣</span>
</td>
<td th:switch="${memorials.memorialsStatus}">
<span th:text="${memorials.memorialsCreateTime}" th:case="0" style="color: red">上疏时间</span>
<span th:text="${memorials.memorialsCreateTime}" th:case="1" style="color: blue">上疏时间</span>
<span th:text="${memorials.memorialsCreateTime}" th:case="2" >上疏时间</span>
</td>
<td th:switch="${memorials.memorialsStatus}">
<span th:case="0" style="color: red">未读</span>
<span th:case="1" style="color: blue">已读</span>
<span th:case="2" >已批示</span>
</td>
<td>
<a th:href="@{/work?(method='memorialsDetail',memorialsId=${memorials.memorialsId})}">奏折详情</a>
</td>
</tr>
</tbody>
</table>
</body>
</html>
4.和登录对接
将authServlet中登录跳转temp的代码替换为刚才做的列表页
resp.sendRedirect(req.getContextPath()+"/work?method=showMemorialsDigestList");
八、业务功能:显示详情
1.详情页代码
<!DOCTYPE html>
<html lang="en" xml:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>temp</title>
<style type="text/css">
table {
border-collapse: collapse;
margin: 0px auto 0px auto;
}
table th, td {
border: 1px solid black;
text-align: center;
}
div {
text-align: center;
}
</style>
</head>
<body>
<!--登录信息部分-->
<div>
<span th:if="${session.loginInfo.empPosition == 'emperor'}">恭请皇上圣安</span>
<span th:if="${session.loginInfo.empPosition == 'minister'}">给<span th:text="${session.loginInfo.empName}"></span>大人请安</span>
<a th:href="@{/auth?method=logout}">退朝</a>
</div>
<!--数据显示部分-->
<table>
<tr>
<td>奏折标题</td>
<td th:text="${memorials.memorialsTitle}"></td>
</tr>
<tr>
<td>上疏大臣</td>
<td th:text="${memorials.memorialsEmpEmpName}"></td>
</tr>
<tr>
<td>上疏时间</td>
<td th:text="${memorials.memorialsCreateTime}"></td>
</tr>
<tr>
<td>奏折内容</td>
<td th:text="${memorials.memorialsContent}"></td>
</tr>
<tr th:if="${memorials.memorialsStatus == 2}">
<td>批复时间</td>
<td th:text="${memorials.feedbackTime}"></td>
</tr>
<tr th:if="${memorials.memorialsStatus == 2}">
<td>批复内容</td>
<td th:text="${memorials.feedbackContent}"></td>
</tr>
</table>
<div th:if="${memorials.memorialsStatus != 2}">
<form th:action="@{/work}" method="post">
<input type="hidden" name="method" value="feedback">
<input type="hidden" name="memorialsId" th:value="${memorials.memorialsId}">
<textarea name="feedbackContent">
</textarea>
<button type="submit">御批</button>
</form>
</div>
<a th:href="@{/work?method=showMemorialsDigestList}">返回列表</a>
</body>
</html>
2.workServlet方法
protected void memorialsDetail(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1。获取请求参数读取 memorialsId
String memorialsId = req.getParameter("memorialsId");
//2.根据memorialsId查询 对象
Memorials memorials = memorialsService.getMemorialsById(memorialsId);
//更新为 已读
if (memorials.getMemorialsStatus() == 0) {
memorialsService.updateMemorialsStatus(memorialsId, 1);
}
//3.放入请求域
req.setAttribute("memorials", memorials);
//解析渲染页面
String templateName = "memorials-detail";
processTemplate(templateName, req, resp);
}
3.MemorialsService方法
Memorials getMemorialsById(String memorialsId);
void updateMemorialsStatus(String memorialsId, int i);
4.MemorialsServiceImpl方法增加
@Override
public Memorials getMemorialsById(String memorialsId) {
return memorialsDao.selectMemorialsById(memorialsId);
}
@Override
public void updateMemorialsStatus(String memorialsId, int i) {
memorialsDao.updateMemorialsStatus(memorialsId,i);
}
5.MemorialsDao方法
Memorials selectMemorialsById(String memorialsId);
void updateMemorialsStatus(String memorialsId, int i);
5.MemorialsDaoImpl方法
@Override
public Memorials selectMemorialsById(String memorialsId) {
String sql = "SELECT\n" +
"\tmemorials_id memorialsId,\n" +
"\tmemorials_title memorialsTitle,\n" +
"\tconcat(left(memorials_content,10),'...') as memorialsContentDigest,\n" +
"\tmemorials_content as memorialsContent,\n" +
"\tmemorials_emp as memorialsEmp,\n" +
"\temp_name as memorialsEmpEmpName,\n" +
"\tmemorials_create_time as memorialsCreateTime,\n" +
"\tfeedback_time as feedbackTime,\n" +
"\tfeedback_content as feedbackContent,\n" +
"\tmemorials_status as memorialsStatus\n" +
"FROM\n" +
"\tt_memorials m\n" +
"\tleft join t_emp e on m.memorials_emp=e.emp_id where m.memorials_id = ?";
return super.getSingleBean(sql,Memorials.class,memorialsId);
}
@Override
public void updateMemorialsStatus(String memorialsId, int i) {
String sql = "update t_memorials set memorials_status = ? where memorials_id = ?";
super.update(sql,i,memorialsId);
}
6. 结果图展示
九、业务功能:回复
1.WorkServlet方法
protected void feedback(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取回复的内容参数
String content = req.getParameter("feedbackContent");
String memorialsId = req.getParameter("memorialsId");
//更新内容
memorialsService.updateFeedback(memorialsId,content);
//重定向到列表页
resp.sendRedirect(req.getContextPath()+"/work?method=showMemorialsDigestList");
}
2.MemorialsService方法
void updateFeedback(String memorialsId, String content);
3.MemorialsServiceImpl方法
@Override
public void updateFeedback(String memorialsId, String content) {
memorialsDao.updateFeedback(memorialsId,content);
}
4.MemorialsDao方法
void updateFeedback(String memorialsId, String content);
5.MemorialsDaoImpl方法
@Override
public void updateFeedback(String memorialsId, String content) {
String sql = "update t_memorials set memorials_status = ? ,feedback_content = ?, feedback_time =? where memorials_id = ?";
String currentTime = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
super.update(sql,2,content,currentTime,memorialsId);
}
十、业务功能:登录检查
1.逻辑
2.创建LoginFilter
package com.sr.maven.filter;
import com.sr.maven.util.ImperialCourtConst;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//1.获取HttpSession
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpSession session = request.getSession();
//尝试从Session域获取已登录的对象
Object loginEmp = session.getAttribute(ImperialCourtConst.LOGIN_EMP_ATTR_NAME);
//判断loginEmp是否为空
if(loginEmp != null){
filterChain.doFilter(request,servletResponse);
return;
}
request.setAttribute("systemMessage",ImperialCourtConst.ACCESS_DENIED_MESSAGE);
request.getRequestDispatcher("/").forward(request,servletResponse);
}
@Override
public void destroy() {
}
}
3.配置web.xml
把LoginFilter放在txFilter前面,一个过滤链的操作,代表前后顺序,节省性能
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.sr.maven.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/work</url-pattern>
</filter-mapping>
十一、打包部署
1.适配环境信息
记得修改对应的配置文件信息,比如数据库地址等,跟环境有关的信息
2.跳过测试打包
mvn clean package -Dmaven.test.skip=true
3.上传war包
自己选择上传到Linux或者Windows等,Tomcat对应的webapp包内
4.启动Tomcat
Linux
tomcat目录/bin/startup.sh
Windows
tomcat目录/bin/startup.bat双击
5.访问测试
自行浏览器地址测试