目录
ViewBaseServlet (Template基础视图类)
难点:通过传递方法标识,反射获取方法,优化代码,将功能封装在一个Servlet 对象内。
通过请求域,实现业务分层之间的数据传递。
注意:定义Servlet时,不要写dogat、dopost方法,否则无法访问执行 ModelBase
一、项目架构图
二、需要实现的功能列表
-
显示首页:浏览器通过index.html访问首页Servlet,然后再解析对应的模板视图
-
显示列表:在首页点击超链接,跳转到目标页面把所有士兵的信息列表显示出来
-
删除信息:在列表上点击删除超链接,执行信息的删除操作
-
新增信息:
-
在列表页面点击超链接跳转到新增士兵信息的表单页面
-
在新增信息的表单页面点击提交按钮执行保存
-
-
更新信息:
-
在列表上点击更新超链接,跳转到更新士兵信息的表单页面:表单回显
-
在更新信息的表单页面点击提交按钮执行更新
-
三、实现代码
1. 动态网页(Template实现)
首页 index.html
<html lang="en" xmlns:th="http://www.thymeleaf.org"> 空间声明
<body>
<h1>首页</h1>
<a th:href="@{/soldier(method='getAll')}">显示士兵列表</a>
</body>
士兵列表 AllSoldiers.html
<body>
<style 样式省略>
<h1>士兵列表</h1>
<table class="imagetable">
<tr>
<th>id</th>
<th>名字</th>
<th>武器</th>
<th>删除</th>
<th>更新</th>
</tr>
<tr th:each="s : ${soldiers}">
<td th:text="${s.soldierId}"></td>
<td th:text="${s.soldierName}"></td>
<td th:text="${s.soldierWeapon}"></td>
<!--携带id参数发起请求-->
<td ><a th:href="@{/soldier(method='deleteSoldier',id=${s.soldierId})}">删除</a></td>
<td><a th:href="@{/soldier(method='toUpdatePage',id=${s.soldierId})}">更新</a></td>
</tr>
</table>
<!--因为Web—Inf内文件中无法直接访问,所以需要通过servlet跳转-->
<a th:href="@{/soldier(method='toAddPage')}">添加士兵</a>
</body>
<h1>添加士兵</h1>
<form action="soldier">
<!--隐藏域,参数为调用的方法名-->
<input type="hidden" name="method" value="addSoldier">
<span>用户名</span><input type="text" name="soldierName">
<spna>武器</spna><input type="text" name="soldierWeapon"> <br>
<input type="submit">
</form>
<h1>修改士兵</h1>
<form action="soldier" align="center">
<input type="hidden" name="method" value="updateSoldier">
<!--隐藏域,不会显示到页面上,但是提交表单时会一起被提交-->
<input type="hidden" name="soldierId" th:value="${soldier.soldierId}">
<span>用户名</span><input type="text" name="soldierName" th:value="${soldier.soldierName}">
<spna>武器</spna><input type="text" name="soldierWeapon" th:value="${soldier.soldierWeapon}">
<input type="submit">
</form>
2. 表述层 (Servlet | Template)
优化:通过反射动态的获取Servlet,调用功能方法
public class ModelBaseServlet extends ViewBaseServlet {
//通过反射获取、调用方法,优化Servlet结构
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
//解决乱码
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//1.this:当前正在请求的Servlet(关键)
Class aClass = this.getClass();
//2.获取方法名
String method = request.getParameter("method");
//3.通过反射获取方法,破坏私有结构
Method declaredMethod = aClass.getDeclaredMethod(method,HttpServletRequest.class,HttpServletResponse.class);
declaredMethod.setAccessible(true);
//4.调用方法
declaredMethod.invoke(this,request,response);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
SoldierServlet 集成所有功能
public class SoldierServlet extends ModelBaseServlet {
//由于不存在get方法,会自动调用父类 (ModelBaseServlet) 中的Get
//通过反射获取调用对应功能方法
//查看列表
private void getAll(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("------- AllSoldierServlet -------");
//1.创建业务层对象
SoldierService soldierService = new SoldierServiceImpl();
//2.调用业务层查询所有方法
List<Soldier> allSolider = soldierService.fubdAllSolider();
//3.将集合添加到请求域中
request.setAttribute("soldiers",allSolider);
processTemplate("AllSoldiers",request,response);
}
//跳转到修改页面的功能
private void toUpdatePage(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("------- ToUpDataSoldierServlet -------");
//1.获取参数id,调用业务层查询对象,最终目的是将数据携带到更新页面
String sid = request.getParameter("id");
int id = Integer.parseInt(sid);
//2.调用业务层查询该对象
SoldierServiceImpl soldierService = new SoldierServiceImpl();
Soldier soldier = soldierService.getSoldierId(id);
//3.将查询到的对象封装到请求域
request.setAttribute("soldier",soldier);
//4.请求转发到更新界面
processTemplate("upSoldier",request,response);
}
//修改功能
private void updateSoldier(HttpServletRequest request, HttpServletResponse response) {
System.out.println("------- updataSoldierServlet -------");
try {
//二、获取全部参数,封装为对象
Map<String, String[]> map = request.getParameterMap();
Soldier soldier = new Soldier();
BeanUtils.populate(soldier,map);
//三、获取业务逻辑层service对象,调用更新方法
SoldierService soldierService = new SoldierServiceImpl();
soldierService.upDataSoldier(soldier);
//五、使用重定向跳转到士兵列表 (修改代码后修改重定向)
response.sendRedirect(request.getContextPath()+"/soldier?method=getAll");
} catch (Exception e) {
e.printStackTrace();
}
}
//删除士兵的功能
private void deleteSoldier(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("------- ToUpDataSoldierServlet -------");
//1.获取参数ID,转为int类型
String sid = request.getParameter("id");
int id = Integer.parseInt(sid);
System.out.println(id);
//2.调用Service 业务逻辑层删除方法,传参id
SoldierService soldierService = new SoldierServiceImpl();
soldierService.deleteSolider(id);
//3.重定向到列表
response.sendRedirect(request.getContextPath()+"/soldier?method=getAll");
}
//跳转到添加页面
private void toAddPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("------- ToAddSoldierPageServlet -------");
processTemplate("addSoldier",request,response);
}
//添加士兵的功能
private void addSoldier(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("------- AddSoldierServlet -------");
//1.获取请求参数
Map<String, String[]> map = request.getParameterMap();
//2.将参数封装为对象
Soldier soldier = new Soldier();
try {
BeanUtils.populate(soldier,map);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(soldier);
//3.创建业务层,调用添加士兵方法
SoldierService soldierService = new SoldierServiceImpl();
soldierService.saveSoldier(soldier);
//4.使用重定向跳转到 AllSoldierServlet 防止重复添加
response.sendRedirect(request.getContextPath()+"/soldier?method=getAll");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
IndexServlet
public class IndexServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("------- indexServlet -------");
processTemplate("index",request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
}
3. 业务逻辑层 (service)
接口 规范
public interface SoldierService {
//查询所有
List<Soldier> fubdAllSolider();
//根据id查询
Soldier getSoldierId(int id);
//删除操作
void deleteSolider(int id);
//添加操作
void saveSoldier(Soldier soldier);
//更新操作
void upDataSoldier(Soldier soldier);
}
实现类
public class SoldierServiceImpl implements SoldierService {
//创建Dao数据访问层对象
SoldierDaoImpl soldierDao = new SoldierDaoImpl();
//查询所有
@Override
public List<Soldier> fubdAllSolider() {
List<Soldier> list = soldierDao.getAll();
return list;
}
//根据id查询
@Override
public Soldier getSoldierId(int id) {
Soldier soldier = soldierDao.getById(id);
return soldier;
}
//删除士兵
@Override
public void deleteSolider(int id) {
soldierDao.deleteById(id);
}
//添加士兵
@Override
public void saveSoldier(Soldier soldier) {
soldierDao.insertSoldier(soldier);
}
//更新
@Override
public void upDataSoldier(Soldier soldier) {
soldierDao.updateSoldier(soldier);
}
}
4. 持久化层(数据访问层 DAO)
public interface SoldierDao {
//删除
void deleteById(int soldierId);
//新增
void insertSoldier(Soldier soldier);
//更新
void updateSoldier(Soldier soldier);
//查询所有
List<Soldier> getAll();
//根据id查询
Soldier getById(int soldierId);
}
public class SoldierDaoImpl extends BaseDaoImpl implements SoldierDao {
//删除
@Override
public void deleteById(int soldierId) {
//注意 ? 没有引号
String sql = "delete from t_soldier where soldier_id = ?";
update(sql,soldierId);
}
//添加
@Override
public void insertSoldier(Soldier soldier) {
String sql = "insert into t_soldier values(null,?,?)";
update(sql,soldier.getSoldierName(),soldier.getSoldierWeapon());
}
//更新
@Override
public void updateSoldier(Soldier soldier) {
String sql = "update t_soldier set soldier_name=?,soldier_weapon=? where soldier_id =?";
update(sql,soldier.getSoldierName(),soldier.getSoldierWeapon(),soldier.getSoldierId());
}
//查询所有
@Override
public List<Soldier> getAll() {
String sql = "select soldier_id soldierid,soldier_name soldiername,soldier_weapon soldierweapon from t_soldier";
List<Soldier> all = findAll(Soldier.class, sql);
return all;
}
//根据id查询
@Override//起别名是为了令数据库的字段名 与 实体类属性名保持一致!
public Soldier getById(int soldierId) {
String sql = "SELECT soldier_id soldierid,soldier_name soldiername,soldier_weapon soldierweapon FROM t_soldier WHERE soldier_id=?";
Soldier soldier = findOneBean(Soldier.class, sql, soldierId);
return soldier;
}
}
5. 其他代码
web.xml配置参数
<!--配置Thymeleaf前后缀-->
<context-param>
<param-name>prefix</param-name>
<param-value>/WEB-INF/view/</param-value>
</context-param>
<context-param>
<param-name>suffix</param-name>
<param-value>.html</param-value>
</context-param>
<!--万能士兵Servlet-->
<servlet>
<servlet-name>SoldierServlet</servlet-name>
<servlet-class>com.atguigu.servlet.SoldierServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SoldierServlet</servlet-name>
<url-pattern>/soldier</url-pattern>
</servlet-mapping>
<!--首页-->
<servlet>
<servlet-name>IndexServlet</servlet-name>
<servlet-class>com.atguigu.servlet.IndexServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>IndexServlet</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
ViewBaseServlet (Template基础视图类)
/**
* 视图基础类 本质还是一个Servlet
*/
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);
// 3.给解析器对象设置参数
// ①HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML);
// ②设置前缀 (重要)
String viewPrefix = servletContext.getInitParameter("prefix");
templateResolver.setPrefix(viewPrefix);
// ③设置后缀 (重要)
String viewSuffix = servletContext.getInitParameter("suffix");
templateResolver.setSuffix(viewSuffix);
// ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
// ⑤设置是否缓存
templateResolver.setCacheable(true);
// ⑥设置服务器端编码方式
templateResolver.setCharacterEncoding("utf-8");
// 4.创建模板引擎对象
templateEngine = new TemplateEngine();
// 5.给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
/**
* 进行视图解析(渲染)的方法
* @param templateName 逻辑视图
* @param req 请求
* @param resp 响应
* @throws IOException
*/
protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType("text/html;charset=UTF-8");
// 2.创建WebContext对象
WebContext webContext = new WebContext(req, resp, getServletContext());
// 3.处理模板数据
templateEngine.process(templateName, webContext, resp.getWriter());
}
}
JDBCUtils (Druid数据库连接池)
public class JDBCUtils {
static DataSource dataSource;
//ThreadLocal,每个线程独有,用于存储共享变量
static ThreadLocal<Connection> local = new ThreadLocal<>();
//静态代码块
static {
//属性集对象
Properties pro = new Properties();
try {
//将配置文件信息 读取到属性集内 (将配置文件信息转为 字节流)
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"));
//通过配置文件创建了链接对象
dataSource = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();
}
}
//通过连接池获取链接
public static Connection getConnection() throws SQLException {
Connection connection = local.get();
//如果ThreadLocalMap内不存在,用连接池获取,存在则直接返回
if(connection==null){
//连接池获取
connection = dataSource.getConnection();
//放入ThreadLocal内
local.set(connection);
}
return connection;
}
//关闭链接方法
public static void closeConnectiopn() throws Exception{
Connection connection = JDBCUtils.getConnection();
//事务关闭,防止后面复用出现问题
connection.setAutoCommit(true);
//删除线程内存储的链接
local.remove();
connection.close();
}
}
BaseDaoImpl (DAO通用的增删改查)
public class BaseDaoImpl {
//通用的BaseDao 通用的增 删 改 查方法
public void update(String sql,Object...params) {
try {
//1.获取链接
Connection connection = JDBCUtils.getConnection();
//2.创建queryRunner
QueryRunner queryRunner = new QueryRunner();
//3.执行操作
queryRunner.update(connection,sql,params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 通用的查询多条数据
* @param clazz 集合的泛型类型
* @param sql
* @param params 参数
* @param <T>
* @return
*/
//不确定查询哪张表,加入泛型!!!!
public <T> List<T> findAll(Class<T> clazz, String sql, Object... params) {
try {
//1.获取链接
Connection connection = JDBCUtils.getConnection();
//2.创建queryRunner
QueryRunner queryRunner = new QueryRunner();
List<T> query = queryRunner.query(connection, sql, new BeanListHandler<>(clazz), params);
return query;
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 通用的返回单个对象
* @param clazz bean的链接类型
* @param sql
* @param params 参数
* @param <T>
* @return
*/
public <T> T findOneBean(Class<T> clazz, String sql, Object... params) {
try {
//1.获取链接
Connection connection = JDBCUtils.getConnection();
//2.创建queryRunner
QueryRunner queryRunner = new QueryRunner();
T bean = queryRunner.query(connection, sql, new BeanHandler<>(clazz), params);
return bean;
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 通用的查询单个值,暂未用到
* @param sql
* @param params
* @return
*/
public Object getSingleValue(String sql,Object...params){
try {
//1.获取链接
Connection connection = JDBCUtils.getConnection();
//2.创建queryRunner
QueryRunner queryRunner = new QueryRunner();
Object query = queryRunner.query(connection, sql, new ScalarHandler<>(), params);
return query;
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
}
Mysql 建表
CREATE TABLE t_soldier(
soldier_id INT PRIMARY KEY AUTO_INCREMENT,
soldier_name CHAR(100),
soldier_weapon CHAR(100)
);