0
点赞
收藏
分享

微信扫一扫

Maven学习(七)单一架构案例

幺幺零 2022-03-23 阅读 26
maven学习

单一架构案例


本章节将以创建一个单一架构的业务系统,从搭建到部署的过程,演示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.访问测试

自行浏览器地址测试
在这里插入图片描述

举报

相关推荐

0 条评论