Maven学习(七)Maven工程单一架构案例
单一架构案例
- 一、创建工程,引入依赖
- 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工程单一架构案例相关推荐
- 2022版Maven教程 - 第六章 单一架构案例
2022版Maven教程 - 第六章 单一架构案例 一.创建工程,引入依赖 1.架构 ①架构的概念 ②单一架构 2.创建工程 3.引入依赖 ①搜索依赖信息的网站 [1]到哪儿找? [2]怎么选择? ② ...
- 【Maven基础】单一架构案例(一)
第一节 创建工程,引入依赖 1.架构 1.1.架构的概念 『架构』其实就是『项目的结构』,只是因为架构是一个更大的词,通常用来形容比较大规模事物的结构. 1.2.单一架构 单一架构也叫『all-in- ...
- Maven学习(一)——Maven入门
为什么80%的码农都做不了架构师?>>> 一.Maven的基本概念 Maven(翻译为"专家","内行")是跨平台的项目管理工具.主要服 ...
- Maven学习(一) - Maven基础
2019独角兽企业重金招聘Python工程师标准>>> Maven作为Java语言的构建和依赖管理工具,已经被广泛使用.但对于maven的pom.xml的配置以及插件的使用,大部分人 ...
- Maven学习(一) --------- Maven 简介
目录 一.软件工程 概述 传统项目开发存在的问题 二.Maven 概述 Maven 优点 构建过程 三.Maven 核心概念 四.安装 Maven 环境 Maven 官网 : http://maven ...
- Maven学习(三)-----Maven本地资源库
Maven本地资源库 Maven的本地资源库是用来存储所有项目的依赖关系(插件jar和其他文件,这些文件被Maven下载)到本地文件夹.很简单,当你建立一个Maven项目,所有相关文件将被存储在你的M ...
- Maven学习(1) - Maven入门
home index:http://maven.apache.org/ download:http://maven.apache.org/download.cgi install: http://ma ...
- maven学习:maven 的入门
2.maven 的入门 到目前为止,我们已经大概了解并安装好了Maven,现在,我们开始创建一个最简单的Hello World项目. 2.1 在Idea创建maven项目 创建一个Maven项目也十分 ...
- 【Maven学习】Maven打包生成包含所有依赖的jar包
http://blog.csdn.net/u013177446/article/details/54134583 ******************************************* ...
- Maven学习(八)-----Maven依赖机制
Maven依赖机制 在 Maven 依赖机制的帮助下自动下载所有必需的依赖库,并保持版本升级. 案例分析 让我们看一个案例研究,以了解它是如何工作的.假设你想使用 Log4j 作为项目的日志.这里你要 ...
最新文章
- asp.net webapi 微信接口接入
- 五十、微信小程序云开发中的云数据库
- 博后招募 | 新加坡国立大学WING实验室招募自然语言处理方向博士后
- mybatis @sqlprovider
- spring websocket基于STOMP协议实现,apache httpd反向代理配置
- mysql btree检索策略_MySQL之Btree索引和HASH索引的区别以及索引优化策略
- oracle处理回车换行符
- 时间序列的截尾和拖尾_R语言:时间序列(一)
- 拦截导弹(信息学奥赛一本通-T1260)
- CVE-2017-11882:Microsoft office 公式编辑器 font name 字段栈溢出通杀漏洞调试分析
- 拉卡拉支付最新支付方式预览——刷脸支付上线
- 国内自动化测试软件,AutoRunner-国内测试行业专业自动化测试工具成长史
- 【WLAN】【基础知识】WIFI那些事儿之DFS
- 地下城与勇士(DNF)异次元裂缝副本(哥布林王国、蠕动之城、兰蒂卢斯的鹰犬、黑色大地、虚无之境 、巴卡尔之城)(童年的回忆)
- (个人翻译)Scrivener交互式手册中文版FowWindows 03基础操作
- python 机器学习 sklearn 朴素贝叶斯
- jupyter 安装插件rise,变为幻灯片PPT格式
- 阿里云国际版设置DNS托管和智能分流教程详解
- 安装Android应用至SD卡
- 几何光学学习笔记(11)- 3.5 理想光学系统的物像关系特性曲线 3.6光学系统的组合
热门文章
- 自动化测试-uiautomatorviewer.bat
- (一)Python小甲鱼入门教程——第一个小游戏001-004
- 解决win10声卡驱动不兼容问题和成功安装战神k650-i5-d2上的Sound Blaster Cinema2在win10系统上
- 双系统装完只能u盘启动_双系统启动引导修复 双系统启动引导设置教程
- win10 安装 hadoop 3.3.1报错 Unable to load native-hadoop library
- 字节跳动实习生转正工资_字节跳动西瓜视频招聘 | 新媒体运营实习生
- Image Matting 图像抠图技术与深度学习抠图
- 实战中,利用10日均线捕捉主升浪,必须满足这四个条件!
- java string 几个字节_java中字符串占几个字节
- AUC(Area under Curve Roc曲线下面积)计算方法总结