最凝练的CRUD
1、建模
①物理建模
CREATE DATABASE `view-demo`CHARACTER SET utf8;
USE `view-demo`;
CREATE TABLE t_soldier(
soldier_id INT PRIMARY KEY AUTO_INCREMENT,
soldier_name CHAR(100),
soldier_weapon CHAR(100)
);
②逻辑建模
public class Soldier {
private Integer soldierId;
private String soldierName;
private String soldierWeapon;
}
2、总体架构
3、搭建持久化层所需环境
①导入jar包
commons-dbutils-1.6.jar
druid-1.1.9.jar
hamcrest-core-1.3.jar
junit-4.12.jar
mysql-connector-java-5.1.37-bin.jar
②创建jdbc.properties
维护基本连接信息
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.198.100:3306/view-demo
username=root
password=atguigu
initialSize=10
maxActive=20
maxWait=10000
③创建JDBCUtils工具类
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JDBCUtil {
// 将数据源对象设置为静态属性,保证大对象的单一实例
private static DataSource dataSource;
static {
// 1.创建一个用于存储外部属性文件信息的Properties对象
Properties properties = new Properties();
// 2.使用当前类的类加载器加载外部属性文件:jdbc.properties
InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
// 3.将外部属性文件jdbc.properties中的数据加载到properties对象中
properties.load(inputStream);
// 4.创建数据源对象
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 从数据源中获取数据库连接
* @return 数据库连接对象
*/
public static Connection getConnection() {
Connection connection = null;
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return connection;
}
/**
* 释放数据库连接
* @param connection 要执行释放操作的连接对象
*/
public static void releaseConnection(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
}
测试能否正常连接数据库:
public class DemoTest {
@Test
public void testConnection() {
Connection connection = JDBCUtil.getConnection();
System.out.println("connection = " + connection);
}
}
④BaseDao
public class BaseDao<T> {
private QueryRunner queryRunner = new QueryRunner();
/**
* 通用的增删改方法
* @param sql
* @param param
* @return
*/
public int update(String sql, Object ... param) {
Connection connection = JDBCUtil.getConnection();
int count = 0;
try {
count = queryRunner.update(connection, sql, param);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
// 关闭数据库连接
JDBCUtil.releaseConnection(connection);
}
return count;
}
/**
* 查询单个对象的通用方法
* @param clazz
* @param sql
* @param param
* @return
*/
public T getBean(Class<T> clazz, String sql, Object ... param) {
Connection connection = JDBCUtil.getConnection();
T bean = null;
try {
bean = queryRunner.query(connection, sql, new BeanHandler<>(clazz), param);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
// 关闭数据库连接
JDBCUtil.releaseConnection(connection);
}
return bean;
}
/**
* 查询集合对象的通用方法
* @param clazz
* @param sql
* @param param
* @return
*/
public List<T> getBeanList(Class<T> clazz, String sql, Object ... param) {
Connection connection = JDBCUtil.getConnection();
List<T> beanList = null;
try {
beanList = queryRunner.query(connection, sql, new BeanListHandler<>(clazz), param);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
} finally {
// 关闭数据库连接
JDBCUtil.releaseConnection(connection);
}
return beanList;
}
}
4、搭建表述层所需环境
本质上就是Thymeleaf所需要的环境
①导入jar包
attoparser-2.0.5.RELEASE.jar
javassist-3.20.0-GA.jar log4j-1.2.15.jar
ognl-3.1.26.jar
slf4j-api-1.7.25.jar
slf4j-log4j12-1.7.25.jar
thymeleaf-3.0.12.RELEASE.jar
unbescape-1.1.6.RELEASE.jar
②创建ViewBaseServlet
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);
// 3.给解析器对象设置参数
// ①HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML);
// ②设置前缀
String viewPrefix = servletContext.getInitParameter("view-prefix");
templateResolver.setPrefix(viewPrefix);
// ③设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");
templateResolver.setSuffix(viewSuffix);
// ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
// ⑤设置是否缓存
templateResolver.setCacheable(true);
// ⑥设置服务器端编码方式
templateResolver.setCharacterEncoding("utf-8");
// 4.创建模板引擎对象
templateEngine = new TemplateEngine();
// 5.给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
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());
}
}
③配置web.xml
<!-- 在上下文参数中配置视图前缀和视图后缀 -->
<context-param>
<param-name>view-prefix</param-name>
<param-value>/WEB-INF/view/</param-value>
</context-param>
<context-param>
<param-name>view-suffix</param-name>
<param-value>.html</param-value>
</context-param>
④创建view目录
5、功能清单
-
显示首页:浏览器通过index.html访问首页Servlet,然后再解析对应的模板视图
-
显示列表:在首页点击超链接,跳转到目标页面把所有士兵的信息列表显示出来
-
删除信息:在列表上点击删除超链接,执行信息的删除操作
-
新增信息:
- 在列表页面点击超链接跳转到新增士兵信息的表单页面
- 在新增信息的表单页面点击提交按钮执行保存
-
更新信息:
- 在列表上点击更新超链接,跳转到更新士兵信息的表单页面:表单回显
- 在更新信息的表单页面点击提交按钮执行更新
6、显示首页
①目标
浏览器访问index.html,通过首页Servlet,渲染视图,显示首页。
②思路
③代码
[1]创建PortalServlet
<servlet>
<servlet-name>PortalServlet</servlet-name>
<servlet-class>com.atguigu.demo.servlet.PortalServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PortalServlet</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
Servlet代码:
public class PortalServlet extends ViewBaseServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String viewName = "portal";
super.processTemplate(viewName, request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
[2]创建portal.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>士兵信息管理系统</title>
</head>
<body>
<a th:href="@{/SoldierServlet?method=showList}">显示士兵信息列表</a>
</body>
</html>
7、显示列表
①目标
在目标页面显示所有士兵信息,士兵信息是从数据库查询出来的
②思路
③代码
[1]ModelBaseServlet
创建这个基类的原因是:我们希望每一个模块能够对应同一个Servlet,
这个模块所需要调用的所有方法都集中在同一个Servlet中。
如果没有这个ModelBaseServlet基类,我们doGet()、doPost()方法可以用来处理请求,
这样一来,每一个方法都需要专门创建一个Servlet(就好比咱们之前的LoginServlet、RegisterServlet其实都应该合并为UserServlet)。
public class ModelBaseServlet extends ViewBaseServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 在doGet()方法中调用doPost()方法,这样就可以在doPost()方法中集中处理所有请求
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.从请求参数中获取method对应的数据
String method = request.getParameter("method");
// 2.通过反射调用method对应的方法
// ①获取Class对象
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, request, response);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
[2]SoldierDao.selectSoldierList()
接口方法:
public interface SoldierDao {
List<Soldier> selectSoldierList();
}
实现类方法:
public class SoldierDaoImpl extends BaseDao<Soldier> implements SoldierDao {
@Override
public List<Soldier> selectSoldierList() {
String sql = "select soldier_id soldierId,soldier_name soldierName,soldier_weapon soldierWeapon from t_soldier";
return getBeanList(Soldier.class, sql);
}
}
[3]SoldierService.getSoldierList()
接口方法:
public interface SoldierService {
List<Soldier> getSoldierList();
}
实现类方法:
public class SoldierServiceImpl implements SoldierService {
private SoldierDao soldierDao = new SoldierDaoImpl();
@Override
public List<Soldier> getSoldierList() {
List<Soldier> soldierList = soldierDao.selectSoldierList();
return soldierList;
}
}
[4]SoldierServlet.showList()
protected void showList(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.调用Service方法获取集合数据
List<Soldier> soldierList = soldierService.getSoldierList();
// 2.将集合数据存入请求域
request.setAttribute("soldierList", soldierList);
// 3.渲染视图(在渲染的过程中,已经包含了转发)
processTemplate("list", request, response);
}
8、删除功能
①目标
点击页面上的超链接,把数据库表中的记录删除。
②思路
[1]先不考虑后续
[2]加上后续返回响应页面
③代码
[1]完成删除超链接
<a th:href="@{/SoldierServlet(soldierId=${soldier.soldierId},method='remove')}">删除</a>
关于@{地址}附加请求参数的语法格式:
- 只有一个请求参数:@{地址(请求参数名=普通字符串)}或@{地址(请求参数名=${需要解析的表达式})}
- 多个请求参数:@{地址(名=值,名=值)}
官方文档中的说明如下:
[2]Servlet方法
protected void remove(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.从请求参数中获取士兵信息的id值
String soldierId = request.getParameter("soldierId");
// 2.调用Service方法执行删除操作
soldierService.remove(soldierId);
// 3.后续……
// 方案一:还是直接前往list.html,需要重新查询soldierList数据,代码重复
// 1.调用Service方法获取集合数据
// List<Soldier> soldierList = soldierService.getSoldierList();
// 2.将集合数据存入请求域
// request.setAttribute("soldierList", soldierList);
// processTemplate("list", request, response);
// 方案二:直接调用隔壁的showList()
// 也能实现需求,但是总感觉这样调用方法破坏了程序的结构
// showList(request, response);
// 方案三:通过请求转发的方式间接调用showList()方法
// request.getRequestDispatcher("/SoldierServlet?method=showList").forward(request, response);
// 方案四:通过请求重定向的方式间接调用showList()方法
response.sendRedirect(request.getContextPath() + "/SoldierServlet?method=showList");
}
[3]Service方法
@Override
public void remove(String soldierId) {
soldierDao.delete(soldierId);
}
[4]Dao方法
@Override
public void delete(String soldierId) {
String sql = "delete from t_soldier where soldier_id=?";
update(sql, soldierId);
}
9、前往新增信息的表单页面
①创建超链接
<a th:href="@{/SoldierServlet?method=toAddPage}">前往新增页面</a>
②Servlet
protected void toAddPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
processTemplate("add-page", request, response);
}
③创建表单页面
<form th:action="@{/SoldierServlet}" method="post">
<input type="hidden" name="method" value="saveSoldier" />
士兵姓名:<input type="text" name="soldierName" /><br/>
士兵武器:<input type="text" name="soldierWeapon" /><br/>
<button type="submit">保存</button>
</form>
10、执行保存
①目标
提交表单后,将表单数据封装为Soldier对象,然后将Soldier对象保存到数据库。
②思路
③代码
[1]Servlet方法
protected void saveSoldier(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取请求参数
String soldierName = request.getParameter("soldierName");
String soldierWeapon = request.getParameter("soldierWeapon");
// 2.创建Soldier对象
Soldier soldier = new Soldier(null, soldierName, soldierWeapon);
// 3.调用Service方法
soldierService.saveSoldier(soldier);
// 4.重定向请求
response.sendRedirect(request.getContextPath() + "/SoldierServlet?method=showList");
}
[2]Service方法
@Override
public void saveSoldier(Soldier soldier) {
soldierDao.insertSoldier(soldier);
}
[3]Dao方法
@Override
public void insertSoldier(Soldier soldier) {
String sql = "insert into t_soldier(soldier_name,soldier_weapon) values(?,?)";
update(sql, soldier.getSoldierName(), soldier.getSoldierWeapon());
}
11、前往修改信息的表单页面
①创建超链接
<a th:href="@{/SoldierServlet(soldierId=${soldier.soldierId},method=toEditPage)}">编辑</a>
②Servlet方法
protected void toEditPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.从请求参数获取soldierId
String soldierId = request.getParameter("soldierId");
// 2.根据soldierId查询Soldier对象
Soldier soldier = soldierService.getSoldierById(soldierId);
// 3.将Soldier对象存入请求域
request.setAttribute("soldier", soldier);
// 4.前往更新的表单页面
processTemplate("edit-page", request, response);
}
③Service方法
@Override
public Soldier getSoldierById(String soldierId) {
return soldierDao.selectSoldierByPrimaryKey(soldierId);
}
④Dao方法
@Override
public Soldier selectSoldierByPrimaryKey(String soldierId) {
String sql = "select soldier_id soldierId,soldier_name soldierName,soldier_weapon soldierWeapon from t_soldier where soldier_id=?";
return getBean(Soldier.class, sql, soldierId);
}
⑤表单页面
<form th:action="@{/SoldierServlet}" method="post">
<input type="hidden" name="method" value="updateSoldier" />
<input type="hidden" name="soldierId" th:value="${soldier.soldierId}" />
士兵姓名:<input type="text" name="soldierName" th:value="${soldier.soldierName}" /><br/>
士兵武器:<input type="text" name="soldierWeapon" th:value="${soldier.soldierWeapon}" /><br/>
<button type="submit">更新</button>
</form>
12、执行更新
①Servlet方法
protected void updateSoldier(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取请求参数
String soldierIdOrigin = request.getParameter("soldierId");
Integer soldierId = Integer.parseInt(soldierIdOrigin);
String soldierName = request.getParameter("soldierName");
String soldierWeapon = request.getParameter("soldierWeapon");
// 2.封装对象
Soldier soldier = new Soldier(soldierId, soldierName, soldierWeapon);
// 3.调用Service方法执行更新
soldierService.updateSoldier(soldier);
// 4.重定向请求
response.sendRedirect(request.getContextPath() + "/SoldierServlet?method=showList");
}
②Service方法
@Override
public void updateSoldier(Soldier soldier) {
soldierDao.updateSoldier(soldier);
}
③Dao方法
@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());
}
13、请求字符集设置
- 设置请求体字符集需要调用request.setCharacterEncoding("UTF-8");
- request.setCharacterEncoding("UTF-8");要求在所有request.getParameter()前面
- 在执行子类Servlet方法时,其实都是先调用父类ModelBaseServlet的doPost()方法
- doPost()方法中包含获取method请求参数的操作
- 所以最前面的request.getParameter()在doPost()方法中
- 所以request.setCharacterEncoding("UTF-8");要放在doPost()方法的request.getParameter()前面
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 0.在所有request.getParameter()前面设置解析请求体的字符集
request.setCharacterEncoding("UTF-8");
// 1.从请求参数中获取method对应的数据
String method = request.getParameter("method");
// ……
本章笔记是观看尚硅谷的JAVAWEB的视频和在网上找的资料 以及自己的理解总结出来的笔记希望可以帮助大家,感谢大家的耐心观看 如有错误请即使联系我 我会及时修正