单一架构案例

  • 一、创建工程,引入依赖
    • 1.架构
      • ①架构的概念
      • ②单一架构
    • 2.创建工程
    • 3. 引入依赖
      • ①搜索依赖信息的网站
      • ②持久化层所需依赖
      • ③表示层所需依赖
      • ④辅助功能所需依赖
      • ⑤最终完整依赖信息
    • 4.建包
  • 二、搭建环境:持久化层
    • 1.数据建模
      • ①物理建模
      • ②逻辑建模
    • 2.数据库连接信息
    • 3.获取数据库连接
      • ①创建JDBCUtils工具类
      • ②创建javax.sql.DataSource对象
      • ③创建ThreadLocal对象
      • ④声明方法:获取数据库连接
      • ⑤声明方法:释放数据库连接
      • ⑥初步测试
    • 4.BaseDao
      • ①泛型的说明
      • ②测试BaseDao
    • 5.子类Dao
      • ①创建接口和实现类
  • 三、搭建环境:事务控制
    • 1.总体思路
    • 2.TransactionFilter
      • ①创建Filter类
      • ②完整代码
      • ③配置web.xml
      • ④注意点
  • 四、搭建环境:表示层
    • 1.视图模板技术Thymeleaf
      • ①服务器端渲染
      • ③逻辑视图与物理视图
      • ④ViewBaseServlet完整代码
      • ⑤增加前缀后缀的web.xml配置
      • ⑥Thymeleaf页面语法
    • 2.ModelBaseServlet
      • ①提出问题
      • ②解决方案
      • ③完整代码
      • ④继承关系
  • 五、搭建环境:辅助功能
    • 1.常量类
    • 2.MD5加密工具类
      • 3.日志配置文件
  • 六、业务功能:登录
    • 1.显示首页
      • ① 流程图
      • ②创建PortalServlet
      • ③在index.html中编写登录页面
    • 2.登录操作
      • ①流程图
      • ②编写EmpDao的方法
      • ③创建EmpService类
      • ④创建登录失败异常
      • ⑤增加一个常量
      • ⑥创建AuthServlet类
      • ⑦temp页面
      • ⑧注册,在web.xml中增加信息
      • ⑨运行结果
    • 3.退出登录
      • ①在临时页面编写超链接
      • ②在AuthServlet编写退出的逻辑
  • 七、业务功能:显示列表
    • 1.流程图
    • 2.创建组件
      • ①创建Java类
      • ② 注册,在web.xml中增加信息
    • 3.页面显示
    • 4.和登录对接
  • 八、业务功能:显示详情
    • 1.详情页代码
    • 2.workServlet方法
    • 3.MemorialsService方法
    • 4.MemorialsServiceImpl方法增加
    • 5.MemorialsDao方法
    • 5.MemorialsDaoImpl方法
    • 6. 结果图展示
  • 九、业务功能:回复
    • 1.WorkServlet方法
    • 2.MemorialsService方法
    • 3.MemorialsServiceImpl方法
    • 4.MemorialsDao方法
    • 5.MemorialsDaoImpl方法
  • 十、业务功能:登录检查
    • 1.逻辑
    • 2.创建LoginFilter
    • 3.配置web.xml
  • 十一、打包部署
    • 1.适配环境信息
    • 2.跳过测试打包
    • 3.上传war包
    • 4.启动Tomcat
    • 5.访问测试

本章节将以创建一个单一架构的业务系统,从搭建到部署的过程,演示Maven项目
完整代码gitee地址:https://gitee.com/reportories/maven_study_all_in_one.git

一、创建工程,引入依赖

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对象是否为nullif (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对象是否为nullif (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 {@Testpublic 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<>();@Testpublic void testGetConnection(){Connection connection = JDBCUtils.getConnection();System.out.println("connection = "+connection);JDBCUtils.releaseConnection(connection);}@Testpublic 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);}@Testpublic 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()));}@Testpublic 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 {@Overridepublic 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");}@Overridepublic 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);}}@Overridepublic 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;@Overridepublic 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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected 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 {@Overrideprotected 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 {@Overridepublic 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();@Overridepublic 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,返回empreturn 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获取HTTPSessionHttpSession 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());//处理视图:indexprocessTemplate("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();@Overridepublic 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 {@Overridepublic 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。获取请求参数读取 memorialsIdString 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方法增加

  @Overridepublic Memorials getMemorialsById(String memorialsId) {return memorialsDao.selectMemorialsById(memorialsId);}@Overridepublic void updateMemorialsStatus(String memorialsId, int i) {memorialsDao.updateMemorialsStatus(memorialsId,i);}

5.MemorialsDao方法

Memorials selectMemorialsById(String memorialsId);void updateMemorialsStatus(String memorialsId, int i);

5.MemorialsDaoImpl方法

   @Overridepublic 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);}@Overridepublic 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方法

  @Overridepublic void updateFeedback(String memorialsId, String content) {memorialsDao.updateFeedback(memorialsId,content);}

4.MemorialsDao方法

void updateFeedback(String memorialsId, String content);

5.MemorialsDaoImpl方法

@Overridepublic 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 {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {//1.获取HttpSessionHttpServletRequest 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);}@Overridepublic 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.访问测试

自行浏览器地址测试

Maven学习(七)Maven工程单一架构案例相关推荐

  1. 2022版Maven教程 - 第六章 单一架构案例

    2022版Maven教程 - 第六章 单一架构案例 一.创建工程,引入依赖 1.架构 ①架构的概念 ②单一架构 2.创建工程 3.引入依赖 ①搜索依赖信息的网站 [1]到哪儿找? [2]怎么选择? ② ...

  2. 【Maven基础】单一架构案例(一)

    第一节 创建工程,引入依赖 1.架构 1.1.架构的概念 『架构』其实就是『项目的结构』,只是因为架构是一个更大的词,通常用来形容比较大规模事物的结构. 1.2.单一架构 单一架构也叫『all-in- ...

  3. Maven学习(一)——Maven入门

    为什么80%的码农都做不了架构师?>>>    一.Maven的基本概念 Maven(翻译为"专家","内行")是跨平台的项目管理工具.主要服 ...

  4. Maven学习(一) - Maven基础

    2019独角兽企业重金招聘Python工程师标准>>> Maven作为Java语言的构建和依赖管理工具,已经被广泛使用.但对于maven的pom.xml的配置以及插件的使用,大部分人 ...

  5. Maven学习(一) --------- Maven 简介

    目录 一.软件工程 概述 传统项目开发存在的问题 二.Maven 概述 Maven 优点 构建过程 三.Maven 核心概念 四.安装 Maven 环境 Maven 官网 : http://maven ...

  6. Maven学习(三)-----Maven本地资源库

    Maven本地资源库 Maven的本地资源库是用来存储所有项目的依赖关系(插件jar和其他文件,这些文件被Maven下载)到本地文件夹.很简单,当你建立一个Maven项目,所有相关文件将被存储在你的M ...

  7. Maven学习(1) - Maven入门

    home index:http://maven.apache.org/ download:http://maven.apache.org/download.cgi install: http://ma ...

  8. maven学习:maven 的入门

    2.maven 的入门 到目前为止,我们已经大概了解并安装好了Maven,现在,我们开始创建一个最简单的Hello World项目. 2.1 在Idea创建maven项目 创建一个Maven项目也十分 ...

  9. 【Maven学习】Maven打包生成包含所有依赖的jar包

    http://blog.csdn.net/u013177446/article/details/54134583 ******************************************* ...

  10. Maven学习(八)-----Maven依赖机制

    Maven依赖机制 在 Maven 依赖机制的帮助下自动下载所有必需的依赖库,并保持版本升级. 案例分析 让我们看一个案例研究,以了解它是如何工作的.假设你想使用 Log4j 作为项目的日志.这里你要 ...

最新文章

  1. asp.net webapi 微信接口接入
  2. 五十、微信小程序云开发中的云数据库
  3. 博后招募 | 新加坡国立大学WING实验室招募自然语言处理方向博士后
  4. mybatis @sqlprovider
  5. spring websocket基于STOMP协议实现,apache httpd反向代理配置
  6. mysql btree检索策略_MySQL之Btree索引和HASH索引的区别以及索引优化策略
  7. oracle处理回车换行符
  8. 时间序列的截尾和拖尾_R语言:时间序列(一)
  9. 拦截导弹(信息学奥赛一本通-T1260)
  10. CVE-2017-11882:Microsoft office 公式编辑器 font name 字段栈溢出通杀漏洞调试分析
  11. 拉卡拉支付最新支付方式预览——刷脸支付上线
  12. 国内自动化测试软件,AutoRunner-国内测试行业专业自动化测试工具成长史
  13. 【WLAN】【基础知识】WIFI那些事儿之DFS
  14. 地下城与勇士(DNF)异次元裂缝副本(哥布林王国、蠕动之城、兰蒂卢斯的鹰犬、黑色大地、虚无之境 、巴卡尔之城)(童年的回忆)
  15. (个人翻译)Scrivener交互式手册中文版FowWindows 03基础操作
  16. python 机器学习 sklearn 朴素贝叶斯
  17. jupyter 安装插件rise,变为幻灯片PPT格式
  18. 阿里云国际版设置DNS托管和智能分流教程详解
  19. 安装Android应用至SD卡
  20. 几何光学学习笔记(11)- 3.5 理想光学系统的物像关系特性曲线 3.6光学系统的组合

热门文章

  1. 自动化测试-uiautomatorviewer.bat
  2. (一)Python小甲鱼入门教程——第一个小游戏001-004
  3. 解决win10声卡驱动不兼容问题和成功安装战神k650-i5-d2上的Sound Blaster Cinema2在win10系统上
  4. 双系统装完只能u盘启动_双系统启动引导修复 双系统启动引导设置教程
  5. win10 安装 hadoop 3.3.1报错 Unable to load native-hadoop library
  6. 字节跳动实习生转正工资_字节跳动西瓜视频招聘 | 新媒体运营实习生
  7. Image Matting 图像抠图技术与深度学习抠图
  8. 实战中,利用10日均线捕捉主升浪,必须满足这四个条件!
  9. java string 几个字节_java中字符串占几个字节
  10. AUC(Area under Curve Roc曲线下面积)计算方法总结