webapp
并整理项目结构;其中:
(1)
api
用来存放servlet
代码;
(2)dao
用来存放数据录操作代码;
(3)listener
用来存放监听器;
(4)util
用来存放工具代码;
(5)model
用来存放实体类代码;
pom.xml
文件并在 maven
面板进行刷新;<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>web-practice</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!--添加servlet依赖包--> <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.12.RELEASE</version> </dependency> <!--添加数据库依赖包--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> </dependencies> <build> <finalName>wp</finalName> </build> </project>
完成上面两步操作后,进行如下操作~
templates
;表白墙.html
, 并放到 WEB-INF/templates
中;代码如下
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="表白墙.css"> </head> <body> <h2>表白墙</h2> <p id="desc">输入后点击提交,会将内容显示在表格中</p> <form action="message" method="post"> <div class="form-row"> <span>谁</span> <input type="text" id="from" name="from"> </div> <div class="form-row"> <span>对谁</span> <!-- name 作为键,输入的内容为值 --> <input type="text" id="to" name="to"> </div> <div class="form-row"> <span>说</span> <input type="text" id="content" name="content"> </div> <div class="form-row"> <!-- 普通按钮,可以使用input type=button,也可以使用button标签 --> <!-- 显示的内容,input按钮是设置为value属性值,button是设置标签内容 --> <input type="submit" id="submit" value="提交"> </div> </form> <p class="row" th:each="m : ${messages}"> <span th:text="${m.from}"></span> <span> 对 </span> <span th:text="${m.to}"></span> <span> 说:</span> <span th:text="${m.content}"></span> </p> </body> </html>
路径为
message
,方法为post
提交的表单格式,post
方法后端解析时不用进行解码操作;
表白墙.css
将其放置在 webapp
目录下;*{ margin: 0; padding: 0; box-sizing: border-box; } h2 { text-align: center; margin: 50px 0; } #desc { text-align: center; font-size: 0.8em; color: gray; margin-bottom: 10px; } .form-row { height: 50px; /* 内容居中: 第一种方式,div有宽度,设置margin */ /* width: 400px; margin: 0 auto; */ /* 第二种方式:div占据整行,设置为弹性布局, 子元素居中 */ display: flex; /* 水平居中 */ justify-content: center; /* 垂直居中:如果子元素高度小于父元素高度 */ align-items: center; } div>span { height: 30px; width: 50px; } div>input { height: 40px; width: 200px; font-size: 22px; line-height: 30px; /* 输入框内容上下不间隔,左右间隔20px */ padding: 0 10px; } #submit { width: 250px; height: 40px; background-color: orange; color: white; /* 消除边框 */ border: none; } /* 按钮点击没有弹起的样式 */ #submit:active { background-color: gray; } .row { text-align: center; }
package org.example.listener; import org.thymeleaf.TemplateEngine; import org.thymeleaf.templateresolver.ServletContextTemplateResolver; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; @WebListener public class TemplateEngineListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { //创建一个模板引擎和解析器 TemplateEngine engine = new TemplateEngine(); //拿到上下文sc ServletContext sc=sce.getServletContext(); ServletContextTemplateResolver resolver =new ServletContextTemplateResolver(sc); //设置属性 resolver.setCharacterEncoding("utf-8"); //设置前缀 resolver.setPrefix("/WEB-INF/templates/"); //设置后缀 resolver.setSuffix(".html"); //将解析器绑定到引擎上 engine.setTemplateResolver(resolver); //将引擎放入上下文环境中,目的:通过上下文路径就可以获取到引擎对象 sc.setAttribute("engine",engine); } @Override public void contextDestroyed(ServletContextEvent sce) { } }
package org.example.api; import org.example.dao.MessageDao; import org.example.model.Message; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.WebContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; //整个表白墙,需要两个后端接口,两个接口1个是获取保存的信息,第2个是提交信息 //实现:可以使用两个servlet不同的路径,也可以是一个路径,不同请求方法 @WebServlet("/message") public class MessageServlet extends HttpServlet { private List<Message> messages = new ArrayList<>(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取表白信息 resp.setContentType("text/html; charset=utf-8"); TemplateEngine engine = (TemplateEngine) getServletContext() .getAttribute("engine"); //表白墙页面展示的时候,就应该显示表白的信息 WebContext wc = new WebContext(req, resp, getServletContext()); // 调整为数据库查询所有表白信息 wc.setVariable("messages", MessageDao.list()); String html = engine.process("表白墙", wc); resp.getWriter().write(html); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); //获取前端提交表白的信息 // post提交表单body格式: from=...&to=...&content=... String from = req.getParameter("from"); String to = req.getParameter("to"); String content = req.getParameter("content"); //保存这些信息:设计为以上三个字段,保存在一个对象的三个属性中,然后把对象放在List中 Message m = new Message(); m.setFrom(from); m.setTo(to); m.setContent(content); //调整为数据库添加一行数据 MessageDao.insertMessage(m); //提交数据后,还需要看到表白墙的页面(其实和访问网页内容的请求是一个逻辑) doGet(req, resp); } }
package org.example.model; //model包:存放实体类(这些类用于转换http数据及数据库的数据) public class Message { private String from; private String to; private String content; @Override public String toString() { return "Message{" + "from='" + from + '\'' + ", to='" + to + '\'' + ", content='" + content + '\'' + '}'; } //生成 getter与setter方法 public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } }
package org.example.dao; import org.example.model.Message; import org.example.util.DBUtil; import org.junit.Test; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; //dao这个名词,是专门做数据操作的(我们这里是做数据库的操作) public class MessageDao { //根据messageServlet.doGet中,需要保存数据的代码 //messages.add(m);需要把m这个message,保存到数据库message表的一行数据 public static void insertMessage(Message m){ //jdbc步骤: Connection c = null; PreparedStatement ps = null; try { //1.获取数据库连接 c = DBUtil.getConnection(); //2.获取操作命令对象 String sql = "insert into message(`from`, `to`, content) values(?,?,?)"; ps = c.prepareStatement(sql); //3.执行sql ps.setString(1, m.getFrom()); ps.setString(2, m.getTo()); ps.setString(3, m.getContent()); int n = ps.executeUpdate(); //4.如果是查询操作,需要处理结果集对象 } catch (SQLException e) { throw new RuntimeException("插入message出错", e); } finally { //5.释放资源 DBUtil.close(c, ps); } } @Test public void testInsertMessage(){ Message m = new Message(); m.setFrom("张三"); m.setTo("李四"); m.setContent("我喜欢你"); insertMessage(m); } //获取所有数据库message表中,保存的数据(多行数据,定义为List<Message为返回值类型) public static List<Message> list(){ List<Message> list = new ArrayList<>(); Connection c = null; PreparedStatement ps = null; ResultSet rs = null; try { //1.获取数据库连接 c = DBUtil.getConnection(); //2.获取操作命令对象 String sql = "select `from`, `to`, content from message"; ps = c.prepareStatement(sql); //3.执行sql rs = ps.executeQuery(); //4.如果是查询操作,需要处理结果集对象 while(rs.next()){//遍历多行数据 //每一行数据,转换为一个message对象,然后放到返回的list里边 Message m = new Message(); String from = rs.getString("from"); String to = rs.getString("to"); String content = rs.getString("content"); m.setFrom(from); m.setTo(to); m.setContent(content); list.add(m); } } catch (SQLException e) { throw new RuntimeException("插入message出错", e); } finally { //5.释放资源 DBUtil.close(c, ps); } return list; } @Test public void testList(){ List<Message> list = list(); System.out.println(list); } }
package org.example.util; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; //数据库工具类:提供获取数据库连接,释放资源的统一代码 public class DBUtil { //静态变量,是类加载的时候初始化,只执行一次 private static MysqlDataSource ds; //一个程序,连接一个数据库,只需要一个连接池,其中保存了多个数据库连接对象 //获取连接池,内部使用,不开放 private static DataSource getDataSource(){ //TODO 有点问题:多线程环境,还有有点问题,留待后续解决 //ds类加载的时候,初始化为null,方法使用的时候,每次都判断一下 if(ds == null) {//判断为空,就创建及初始化属性 ds = new MysqlDataSource(); ds.setURL("jdbc:mysql://localhost:3306/biaobai"); ds.setUser("root"); ds.setPassword("123456"); ds.setUseSSL(false);//不安全连接,如果不设置,也不影响,只是有警告 ds.setCharacterEncoding("UTF-8"); } return ds; } //获取数据库连接对象:开放给外部的jdbc代码使用 public static Connection getConnection(){ try { return getDataSource().getConnection(); } catch (SQLException e) { throw new RuntimeException("获取数据库连接出错,可能是url,账号密码写错了", e); } } //查询操作需要释放三个资源,更新操作(插入,修改,删除)只需要释放前两个资源 public static void close(Connection c, Statement s, ResultSet r) { try { if (r != null) r.close(); if (s != null) s.close(); if (c != null) c.close(); } catch (SQLException e) { throw new RuntimeException("释放资源出错", e); } } //提供更新操作方便的释放资源功能 public static void close(Connection c, Statement s){ close(c, s, null); } public static void main(String[] args) { System.out.println(getConnection()); } }
初始化数据库操作,将其放入resources
下:
drop database if exists biaobai; create database biaobai character set utf8mb4; use biaobai; create table message( `from` varchar(20), `to` varchar(20), `content` varchar(200) );
启动服务器,运行显示:
不管什么功能,使用模板技术:
前端需要做的事情:
考虑如何发请求
;如以上发请求的方式为:
- 浏览器地址栏输入
URL
;- 表单提交;
对应后端需要考虑的事情:
(1)获取请求数据
:如以上第一个功能没有请求数据所以不用管,而第二个功能是提交数据,因此要解析请求数据;
(2)执行需要的业务逻辑
:如以上第一个功能没有逻辑;第二个需要保存数据;
(3)返回响应
:如以上两个功能都需要返回表白墙网页+list
数据,渲染动态html
网页;