物理视图:
/pages/user/login.html
/pages/user/login_success.html
/pages/user/regist.html
/pages/user/regist_success.html
逻辑视图:
物理视图=视图前缀+逻辑视图+视图后缀
视图前缀 | 逻辑视图 | 视图后缀 | 物理视图 |
/pages/user/ | login | .html | /pages/user/login.html |
/pages/user/ | login_success | .html | /pages/user/login_success.html |
Thymeleaf需要入导入的jar包
配置上下文参数
物理视图=视图前缀+逻辑视图+视图后缀
<!-- 在上下文参数中配置视图前缀和视图后缀 -->
<context-param>
<param-name>view-prefix</param-name>
<param-value>/pages/</param-value>
</context-param>
<context-param>
<param-name>view-suffix</param-name>
<param-value>.html</param-value>
</context-param>
1.为什么要放在WEB-INF目录下?
原因:WEB-INF目录不允许浏览器直接访问,所以我们的视图模板文件放在这个目录下,是一种保护。以免外界可以随意访问视图模板文件。
2.访问WEB-INF目录下的页面,都必须通过Servlet转发过来,简单说就是:不经过Servlet访问不了。
这样就方便我们在Servlet中检查当前用户是否有权限访问。
3.那放在WEB-INF目录下之后,重定向进不去怎么办?
重定向到Servlet,再通过Servlet转发到WEB-INF下。
创建Servlet基类
package com.softeem.servlet;
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;
import java.io.PrintWriter;
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");/* /pages */
templateResolver.setPrefix(viewPrefix);
// ③设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");/* .html */
templateResolver.setSuffix(viewSuffix);
// ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
// ⑤设置是否缓存
templateResolver.setCacheable(true);//我是建议设置成false
// ⑥设置服务器端编码方式
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");//输出流.向浏览器转出数据时防止乱码
PrintWriter out = resp.getWriter();
ServletContext servletContext = this.getServletContext();//容器上下文对象
// 2.创建WebContext对象
WebContext webContext = new WebContext(req, resp, servletContext);
// 3.处理模板数据
templateEngine.process(templateName, webContext, out);
}
}
过能Servlet请求转发访问与直接访问区别
<p th:text="张无忌">张三丰</p>
①th:text作用
- 不经过服务器解析,直接用浏览器打开HTML文件,看到的是『张三丰』
- 经过服务器解析,Thymeleaf引擎根据th:text属性指定的『张无忌』去替换『张三丰』
②字面量
『字面量』是一个经常会遇到的概念,我们可以对照『变量』来理解它的含义。
// a是变量,100是字面量
int a = 100;
System.out.println("a = " + a);
- 变量:变量名字符串本身不是它的值,它指向的才是它的值
- 字面量:它就是字面上的含义,我们从『字面』上看到的直接就是它的值
注意: 现在我们在th:text属性中使用的就是『字面量』,它不指代任何其他值。
修改指定属性值
<input type="text" name="username" th:value="张无忌" value="张三丰" />
语法:任何HTML标签原有的属性,前面加上『th:』就都可以通过Thymeleaf来设定新值。
解析URL地址
@{/}的作用是在字符串前附加『上下文路径』
@{/}表示是你当然的项目名 /ThymeleafDemo
// 1.声明当前请求要前往的视图名称
String viewName = "target";
/*往req请求中保存一个属性
名称:reqAttrName
值: <span>hello-value</span>
*/
req.setAttribute("reqAttrName", "<span style='color:red'>hello-value</span>");
// 2.调用ViewBaseServlet父类中的解析视图模板的方法,此方法一定在最末尾处
super.processTemplate(viewName, req, resp);
<p>有转义效果:[[${reqAttrName}]]</p>
<p>无转义效果:[(${reqAttrName})]</p>
th:text效果<p th:text="${reqAttrName}"></p>
th:utext效果<p th:utext="${reqAttrName}"></p>
1、域对象
①请求域*****
在请求转发的场景下,我们可以借助HttpServletRequest对象内部给我们提供的存储空间,帮助我们携带数据,把数据发送给转发的目标资源。
通俗的说讲就是: 把服务中的数据传递到网页
我们使用request请求域来保存一些数据
@WebServlet("/RegionServlet")
public class RegionServlet extends ViewBaseServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("username" , "裴杰");
req.setAttribute("password" , "123456");
req.setAttribute("phone" , "13886082121");
// 2.调用ViewBaseServlet父类中的解析视图模板的方法
super.processTemplate("region", req, resp);
}
}
<h1>请求域测试取值</h1>
用户名:<input type="text" th:value="${username}"><br/>
密码:<input type="text" th:value="${password}"><br/>
手机:<input type="text" th:value="${phone}"><br/>
<div>[[${username}]]</div>
<div>[[${password}]]</div>
<div>[[${phone}]]</div>
<h1 th:text="${password}"></h1>
<h1 th:text="${username}"></h1>
<h1 th:text="${phone}"></h1>
请求域时间最短,范围也是最小的.一次请求内有效,请求完成.请求域中的数据就失效了
②会话域****
设置session的超时时间
<session-config>
<!-- session超时,时间设置,默认就是30分钟.
可以根据实际情况设置超时,时间长短-->
<session-timeout>30</session-timeout>
</session-config>
//通过request对象获取HttpSession对象 : session
HttpSession session = req.getSession();
session.setAttribute("username" , "张三");
session.setAttribute("password" , "987654");
session.setAttribute("phone" , "13612345678");
<h1>会话域测试取值</h1>
用户名:<input type="text" th:value="${session.username}"><br/>
密码:<input type="text" th:value="${session.password}"><br/>
手机:<input type="text" th:value="${session.phone}"><br/>
<div>[[${session.username}]]</div>
<div>[[${session.password}]]</div>
<div>[[${session.phone}]]</div>
<h1 th:text="${session.password}"></h1>
<h1 th:text="${session.username}"></h1>
<h1 th:text="${session.phone}"></h1>
session会话域: 默认可以保存30分钟数据有效果,但是前提是不要关闭浏览器.如果关掉浏览器会在去访问.就访问不到session中的数据了.原因是跟cookie有关.但是我们现在还没有讲到cookie,我们后面讲完cookie会来解释失效的原因
③应用域(使用比较少)
//上下文对象 -> 应该域 -> 全局作用域
ServletContext servletContext = getServletContext();
servletContext.setAttribute("username" , "李四");
servletContext.setAttribute("password" , "101010");
servletContext.setAttribute("phone" , "1377777777");
页面取值时使用 ${application.xxxx} 这个application就是我们Serlvet类中的ServletContext对象
<h1>应用域测试取值</h1>
用户名:<input type="text" th:value="${application.username}"><br/>
密码:<input type="text" th:value="${application.password}"><br/>
手机:<input type="text" th:value="${application.phone}"><br/>
<div>[[${application.username}]]</div>
<div>[[${application.password}]]</div>
<div>[[${application.phone}]]</div>
<h1 th:text="${application.password}"></h1>
<h1 th:text="${application.username}"></h1>
<h1 th:text="${application.phone}"></h1>
应该域生命周期更长 他是与服务器生命一样长.只要服务器不关.保存到应该域中的数据会一直有效,直到你关闭服务器.[人在塔在] --> [服务器在应该域]
页面也能获取请求参数
<a href="RequestParamServlet?username=tom">请求参数测试</a><br/>
package com.softeem.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/RequestParamServlet")
public class RequestParamServlet extends ViewBaseServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");//解决post乱码
//获取请求参数param
String username = req.getParameter("username");
System.out.println("username = " + username);
//跳转页面pages/param.html
super.processTemplate("param" , req ,resp);
}
}
<body>
<h1>我是param网页</h1>
<p th:text="${param.username}">这里替换为请求参数的值</p>
</body>
效果图:
接收到参数tom
如果接收的请求参数为空字符 或者 null
请求时传入了username参数,但是此参数并且没有数据,此时服务端接收的是一个空字符串,在页面接收此username参数时,是不显示任何结果的
请求时没有传入了username参数,此时服务端接收的是null,在页面接收此username参数时,也是不显示任何结果的
一个参数多个值
<a href="RequestParamServlet?hobby=足球&hobby=篮球&hobby=排球">请求参数[多个值]测试</a><br/>
package com.softeem.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
@WebServlet("/RequestParamServlet")
public class RequestParamServlet extends ViewBaseServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");//解决post乱码
//获取请求参数param
String username = req.getParameter("username");
System.out.println("username = " + username);
//一个参数多个值.取值时要使用getParameterValues()方法
//如果还使用getParameter()方法,只能获取第一个值,后面其它时获取不到
String[] hobby = req.getParameterValues("hobby");
System.out.println(Arrays.toString(hobby));
//跳转页面pages/param.html
super.processTemplate("param" , req ,resp);
}
}
可以通过下标的方式来取值
<p th:text="${param.hobby[0]}">这里替换为请求参数的值</p>
<p th:text="${param.hobby[1]}">这里替换为请求参数的值</p>
<p th:text="${param.hobby[2]}">这里替换为请求参数的值</p>
加入log4j.properties日志文件,放到src目录下
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:\\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
内置对象
#request
<h3>表达式的基本内置对象</h3>
<p th:text="${#request.getClass().getName()}">这里显示#request对象的全类名</p>
<p th:text="${#request.getContextPath()}">调用#request对象的getContextPath()方法</p>
<p th:text="${#request.getAttribute('helloRequestAttr')}">调用#request对象的getAttribute()方法,读取属性域</p>
基本思路:
- 如果不清楚这个对象有哪些方法可以使用,那么就通过getClass().getName()获取全类名,再回到Java环境查看这个对象有哪些方法
- 内置对象的方法可以直接调用
- 调用方法时需要传参的也可以直接传入参数
公共内置对象
#lists
req.setAttribute("aNotEmptyList", Arrays.asList("aaa","bbb","ccc"));
req.setAttribute("anEmptyList", new ArrayList<>());
<h1>#lists使用</h1>
<p>#list对象isEmpty方法判断集合整体是否为空aNotEmptyList:
<span th:text="${#lists.isEmpty(aNotEmptyList)}">测试#lists</span></p>
<p>#list对象isEmpty方法判断集合整体是否为空anEmptyList:
<span th:text="${#lists.isEmpty(anEmptyList)}">测试#lists</span></p>
<p>#lists对象contains方法判断集合中是否有aaa:
<span th:text="${#lists.contains(aNotEmptyList , 'aaa')}"></span>
</p>
<p>#lists对象size方法,获取集合中的元素个数
<span th:text="${#lists.size(aNotEmptyList)}"></span>
</p>
基本语法:${}中的表达式本质是OGNL
实验需要用到的类
package com.softeem.bean;
public class Teacher {
private String teacherName;
public Teacher() {
}
public Teacher(String teacherName) {
this.teacherName = teacherName;
}
/**
* 获取
* @return teacherName
*/
public String getTeacherName() {
return teacherName;
}
/**
* 设置
* @param teacherName
*/
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
public String toString() {
return "Teacher{teacherName = " + teacherName + "}";
}
}
package com.softeem.bean;
public class Subject {
private String subjectName;
public Subject() {
}
public Subject(String subjectName) {
this.subjectName = subjectName;
}
/**
* 获取
* @return subjectName
*/
public String getSubjectName() {
return subjectName;
}
/**
* 设置
* @param subjectName
*/
public void setSubjectName(String subjectName) {
this.subjectName = subjectName;
}
public String toString() {
return "Subject{subjectName = " + subjectName + "}";
}
}
package com.softeem.bean;
public class School {
private String schoolName ;
public School() {
}
public School(String schoolName) {
this.schoolName = schoolName;
}
/**
* 获取
* @return schoolName
*/
public String getSchoolName() {
return schoolName;
}
/**
* 设置
* @param schoolName
*/
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public String toString() {
return "School{schoolName = " + schoolName + "}";
}
}
package com.softeem.bean;
import java.util.List;
import java.util.Map;
public class Student {
private String studentName;
private Subject subject ;
private List<School> schoolList;
private Map<String,Teacher> teacherMap;
public Student() {
}
public Student(String studentName, Subject subject, List<School> schoolList, Map<String, Teacher> teacherMap) {
this.studentName = studentName;
this.subject = subject;
this.schoolList = schoolList;
this.teacherMap = teacherMap;
}
/**
* 获取
* @return studentName
*/
public String getStudentName() {
return studentName;
}
/**
* 设置
* @param studentName
*/
public void setStudentName(String studentName) {
this.studentName = studentName;
}
/**
* 获取
* @return subject
*/
public Subject getSubject() {
return subject;
}
/**
* 设置
* @param subject
*/
public void setSubject(Subject subject) {
this.subject = subject;
}
/**
* 获取
* @return schoolList
*/
public List<School> getSchoolList() {
return schoolList;
}
/**
* 设置
* @param schoolList
*/
public void setSchoolList(List<School> schoolList) {
this.schoolList = schoolList;
}
/**
* 获取
* @return teacherMap
*/
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
/**
* 设置
* @param teacherMap
*/
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}
public String toString() {
return "Student{studentName = " + studentName + ", subject = " + subject + ", schoolList = " + schoolList + ", teacherMap = " + teacherMap + "}";
}
}
网页取值演示代码:
<h1>属性访问语法测试</h1>
<!-- 也可以调用setStudentName()方法给学生名赋值 -->
<span th:text="${s.setStudentName('小芳')}"></span>
学生姓名:<span th:text="${s.studentName}"></span>
<span th:text="${s.getStudentName()}"></span><br/>
主题名:<span th:text="${s.subject.subjectName}"></span>
<span th:text="${s.getSubject().getSubjectName()}"></span><br/>
学校名:<span th:text="${s.schoolList[0].schoolName}"></span>
<span th:text="${s.schoolList[1].schoolName}"></span>
<span th:text="${s.schoolList[2].schoolName}"></span>
<span th:text="${s.getSchoolList().get(0).getSchoolName()}"></span>
<span th:text="${s.getSchoolList().get(1).getSchoolName()}"></span>
<span th:text="${s.getSchoolList().get(2).getSchoolName()}"></span><br/>
<!-- map使用方法取值不演示了.一样的操作流程 -->
老师名:<span th:text="${s.teacherMap.A1.teacherName}"></span>
<span th:text="${s.teacherMap.B2.teacherName}"></span>
<span th:text="${s.teacherMap['A1'].teacherName}"></span>
<span th:text="${s.teacherMap['B2'].teacherName}"></span>
取值效果如图:
关于怎么访问类中私有属性的问题?
分支与迭代
1、分支*****
①if
示例的实体类:
package com.softeem.bean;
public class Employee {
private Integer empId;
private String empName;
private Double empSalary;
public Employee() {
}
public Employee(Integer empId, String empName, Double empSalary) {
this.empId = empId;
this.empName = empName;
this.empSalary = empSalary;
}
/**
* 获取
* @return empId
*/
public Integer getEmpId() {
return empId;
}
/**
* 设置
* @param empId
*/
public void setEmpId(Integer empId) {
this.empId = empId;
}
/**
* 获取
* @return empName
*/
public String getEmpName() {
return empName;
}
/**
* 设置
* @param empName
*/
public void setEmpName(String empName) {
this.empName = empName;
}
/**
* 获取
* @return empSalary
*/
public Double getEmpSalary() {
return empSalary;
}
/**
* 设置
* @param empSalary
*/
public void setEmpSalary(Double empSalary) {
this.empSalary = empSalary;
}
public String toString() {
return "Employee{empId = " + empId + ", empName = " + empName + ", empSalary = " + empSalary + "}";
}
}
package com.softeem.servlet;
import com.softeem.bean.Employee;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/BranchServlet")
public class BranchServlet extends ViewBaseServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.创建ArrayList对象并填充
List<Employee> employeeList = new ArrayList<>();
employeeList.add(new Employee(1, "tom", 500.00));
employeeList.add(new Employee(2, "jerry", 600.00));
employeeList.add(new Employee(3, "harry", 700.00));
employeeList.add(new Employee(4, "张三", 800.00));
employeeList.add(new Employee(5, "李四", 900.00));
// 2.将集合数据存入请求域
req.setAttribute("employeeList", employeeList);
// 3.调用父类方法渲染视图
super.processTemplate("branch", req, resp);
}
}
<h2>分支if</h2>
<table border="1">
<tr>
<th>员工编号</th>
<th>员工姓名</th>
<th>员工工资</th>
</tr>
<tr th:if="${#lists.isEmpty(employeeList)}">
<td colspan="3">抱歉!没有查询到你搜索的数据!</td>
</tr>
<tr th:if="${not #lists.isEmpty(employeeList)}">
<td colspan="3">if我是有数据的!</td>
</tr>
<tr th:unless="${#lists.isEmpty(employeeList)}">
<td colspan="3">unless有数据!</td>
</tr>
</table>
演示效果如图:
②switch
在添加一个User类
package com.softeem.bean;
public class User {
private String username ;//会员姓名
private String memberLevel;//会员等级
public User() {
}
public User(String username, String memberLevel) {
this.username = username;
this.memberLevel = memberLevel;
}
/**
* 获取
* @return username
*/
public String getUsername() {
return username;
}
/**
* 设置
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取
* @return memberLevel
*/
public String getMemberLevel() {
return memberLevel;
}
/**
* 设置
* @param memberLevel
*/
public void setMemberLevel(String memberLevel) {
this.memberLevel = memberLevel;
}
public String toString() {
return "User{username = " + username + ", memberLevel = " + memberLevel + "}";
}
}
BranchServlet类中的service方法添加代码
User user = new User("小黄" , "level-3");
req.setAttribute("user" , user);
<h2>分支switch</h2>
<h3>测试switch</h3>
<div th:switch="${user.memberLevel}">
[[${user.username}]]
<p th:case="level-1">银牌会员</p>
<p th:case="level-2">金牌会员</p>
<p th:case="level-3">白金会员</p>
<p th:case="level-4">钻石会员</p>
</div>
效果如图:
2、迭代*****
<h3>测试each</h3>
<table border="1">
<thead>
<tr>
<th>员工编号</th>
<th>员工姓名</th>
<th>员工工资</th>
<th>下标</th>
<th>数量</th>
<th>大小</th>
<th>当前对象</th>
<th>奇数</th>
<th>偶数</th>
<th>第一个</th>
<th>最后一个</th>
</tr>
</thead>
<tbody th:if="${#lists.isEmpty(employeeList)}">
<tr>
<td colspan="3">抱歉!没有查询到你搜索的数据!</td>
</tr>
</tbody>
<tbody th:if="${not #lists.isEmpty(employeeList)}">
<!-- 遍历出来的每一个元素的名字 : ${要遍历的集合} -->
<tr th:each="emp,empStatus : ${employeeList}">
<td th:text="${emp.empId}">empId</td>
<td th:text="${emp.empName}">empName</td>
<td th:text="${emp.empSalary}">empSalary</td>
<!--以下代码是这个集合状态代码不是每次遍历数据都会有用
一般是根据我们的需要使用.不会像我们现在这样全部显示出来-->
<td th:text="${empStatus.index}">empSalary</td>
<td th:text="${empStatus.count}">empSalary</td>
<td th:text="${empStatus.size}">empSalary</td>
<td th:text="${empStatus.current}">empSalary</td>
<td th:text="${empStatus.even}">empSalary</td>
<td th:text="${empStatus.odd}">empSalary</td>
<td th:text="${empStatus.first}">empSalary</td>
<td th:text="${empStatus.last}">empSalary</td>
</tr>
</tbody>
</table>
效果如图:
基本语法:包含其他模板文件
创建MainServlet类
package com.softeem.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/MainServlet")
public class MainServlet extends ViewBaseServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.processTemplate("main",req,resp);
}
}
创建common.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:fragment="header" style="border: 2px red solid">
<p>被抽取出来的头部内容</p>
</div>
<div th:fragment="tail" style="border: 2px blue dashed">
<p>被抽取出来的尾部内容...</p>
</div>
<div th:fragment="left" style="border: 2px pink double">
<p>被抽取出来的左则边内容...</p>
</div>
</body>
</html>
创建main.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 代码片段所在页面的逻辑视图 :: 代码片段的名称 -->
<div id="badBoy" th:insert="common :: header" style="border: 2px greenyellow solid">
div标签的原始内容
</div>
<h1>我是一个main.html</h1>
<div id="worseBoy" th:replace="common :: tail" style="border: 2px greenyellow solid">
div标签的原始内容
</div>
<div id="testBoy" th:include="common :: left" style="border: 2px greenyellow solid">
div标签的原始内容
</div>
</body>
</html>
效果如图:
网页源码部分:
玩转 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 VARCHAR(100),
soldier_weapon VARCHAR(100)
);
创建一个新的项目.结构与jar包,还有有工具类如图:
②逻辑建模
package com.softeem.bean;
public class Soldier {
private Integer soldierId;
private String soldierName;
private String soldierWeapon;
public Soldier() {
}
public Soldier(Integer soldierId, String soldierName, String soldierWeapon) {
this.soldierId = soldierId;
this.soldierName = soldierName;
this.soldierWeapon = soldierWeapon;
}
/**
* 获取
* @return soldierId
*/
public Integer getSoldierId() {
return soldierId;
}
/**
* 设置
* @param soldierId
*/
public void setSoldierId(Integer soldierId) {
this.soldierId = soldierId;
}
/**
* 获取
* @return soldierName
*/
public String getSoldierName() {
return soldierName;
}
/**
* 设置
* @param soldierName
*/
public void setSoldierName(String soldierName) {
this.soldierName = soldierName;
}
/**
* 获取
* @return soldierWeapon
*/
public String getSoldierWeapon() {
return soldierWeapon;
}
/**
* 设置
* @param soldierWeapon
*/
public void setSoldierWeapon(String soldierWeapon) {
this.soldierWeapon = soldierWeapon;
}
public String toString() {
return "Soldier{soldierId = " + soldierId + ", soldierName = " + soldierName + ", soldierWeapon = " + soldierWeapon + "}";
}
}
2、总体架构
3、搭建持久化层所需环境
①导入jar包
attoparser-2.0.5.RELEASE.jar
commons-dbutils-1.7.jar
commons-logging-1.1.1.jar
druid-1.1.10.jar
hamcrest-core-1.3.jar
javassist-3.20.0-GA.jar
junit-4.12.jar
log4j-1.2.17.jar
mysql-connector-java-5.1.37.jar
ognl-3.1.26.jar
servlet-api.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
②创建jdbc.properties
username=root
password=123456
url=jdbc:mysql://localhost:3306/view-demo?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
③配置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目录
6、显示首页
①目标
浏览器访问index.html,通过首页Servlet,渲染视图,显示首页。
②思路
③代码
[1]创建PortalServlet
package com.softeem.servlet;
import com.softeem.utils.ViewBaseServlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/index.html")
public class PortalServlet extends ViewBaseServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String viewName = "portal";
super.processTemplate(viewName, req, resp);
}
}
说明:为什么我要把PortalServlet的url设置成index.html?
我们访问index.html网页还要去点击连接请求一个Servlet类.在使用servlet类帮我们进行请求转发.这样做还会多一次点击连接的操作.
所以我们干脆把servlet类起个名字[url]就叫做index.html.这样服务启动后直接就访问的是Servlet类.直接就可以请求转发到我们想去的网页.少了一次点击的过程
[2]创建portal.html
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>
package com.softeem.utils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ModelBaseServlet extends ViewBaseServlet{
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//解决post请求乱码
req.setCharacterEncoding("utf-8");
//获取一个请求参数.只参数是方法
String method = req.getParameter("method");
//获取当前类的.类描述对象,回去想一下this是谁???
Class claxx = this.getClass();
try {
//获取要请求的方法对象
Method declaredMethod = claxx.getDeclaredMethod(method HttpServletRequest.class, HttpServletResponse.class);
declaredMethod.setAccessible(true);//关闭访问权限检查
declaredMethod.invoke(this , req,resp);//执行方法
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
package com.softeem.servlet;
import com.softeem.utils.ModelBaseServlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/SoldierServlet")
public class SoldierServlet extends ModelBaseServlet {
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("SoldierServlet.add");
}
protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("SoldierServlet.update");
}
protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("SoldierServlet.delete");
}
protected void find(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("SoldierServlet.find");
}
}
<!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>-->
<a th:href="@{/SoldierServlet?method=add}">显示士兵信息列表添加</a>
<a th:href="@{/SoldierServlet?method=update}">显示士兵信息列表修改</a>
<a th:href="@{/SoldierServlet?method=delete}">显示士兵信息列表删除</a>
<a th:href="@{/SoldierServlet?method=find}">显示士兵信息列表查询</a>
</body>
</html>
现在我们后端代码的执行流程1
现在我们后端代码的执行流程2
士兵管理的查询功能
t_soldier表多添加了三个字段.为我后续实现多条件分页查询做准备
javaBean重新生成一下
package com.softeem.bean;
import java.sql.Date;
public class Soldier {
private Integer soldierId;
private String soldierName;
private String soldierWeapon;
private String soldierSex;
private Integer soldierAge;
private Date soldierBirthday;
public Soldier() {
}
public Soldier(Integer soldierId, String soldierName, String soldierWeapon, String soldierSex, Integer soldierAge, Date soldierBirthday) {
this.soldierId = soldierId;
this.soldierName = soldierName;
this.soldierWeapon = soldierWeapon;
this.soldierSex = soldierSex;
this.soldierAge = soldierAge;
this.soldierBirthday = soldierBirthday;
}
/**
* 获取
* @return soldierId
*/
public Integer getSoldierId() {
return soldierId;
}
/**
* 设置
* @param soldierId
*/
public void setSoldierId(Integer soldierId) {
this.soldierId = soldierId;
}
/**
* 获取
* @return soldierName
*/
public String getSoldierName() {
return soldierName;
}
/**
* 设置
* @param soldierName
*/
public void setSoldierName(String soldierName) {
this.soldierName = soldierName;
}
/**
* 获取
* @return soldierWeapon
*/
public String getSoldierWeapon() {
return soldierWeapon;
}
/**
* 设置
* @param soldierWeapon
*/
public void setSoldierWeapon(String soldierWeapon) {
this.soldierWeapon = soldierWeapon;
}
/**
* 获取
* @return soldierSex
*/
public String getSoldierSex() {
return soldierSex;
}
/**
* 设置
* @param soldierSex
*/
public void setSoldierSex(String soldierSex) {
this.soldierSex = soldierSex;
}
/**
* 获取
* @return soldierAge
*/
public Integer getSoldierAge() {
return soldierAge;
}
/**
* 设置
* @param soldierAge
*/
public void setSoldierAge(Integer soldierAge) {
this.soldierAge = soldierAge;
}
/**
* 获取
* @return soldierBirthday
*/
public Date getSoldierBirthday() {
return soldierBirthday;
}
/**
* 设置
* @param soldierBirthday
*/
public void setSoldierBirthday(Date soldierBirthday) {
this.soldierBirthday = soldierBirthday;
}
public String toString() {
return "Soldier{soldierId = " + soldierId + ", soldierName = " + soldierName + ", soldierWeapon = " + soldierWeapon + ", soldierSex = " + soldierSex + ", soldierAge = " + soldierAge + ", soldierBirthday = " + soldierBirthday + "}";
}
}
SoldierDao接口
package com.softeem.dao;
import com.softeem.bean.Soldier;
import java.util.List;
public interface SoldierDao {
List<Soldier> selectSoldierList();
}
SoldierDaoImpl实现
package com.softeem.dao.impl;
import com.softeem.bean.Soldier;
import com.softeem.dao.SoldierDao;
import com.softeem.utils.BaseDao;
import java.util.List;
public class SoldierDaoImpl extends BaseDao<Soldier> implements SoldierDao {
@Override
public List<Soldier> selectSoldierList() {
return super.getBeanList("select * from t_soldier");
}
}
SoldierService接口
package com.softeem.service;
import com.softeem.bean.Soldier;
import java.util.List;
public interface SoldierService {
List<Soldier> getSoldierList();
}
SoldierServiceImpl实现
package com.softeem.service.impl;
import com.softeem.bean.Soldier;
import com.softeem.dao.SoldierDao;
import com.softeem.dao.impl.SoldierDaoImpl;
import com.softeem.service.SoldierService;
import java.util.List;
public class SoldierServiceImpl implements SoldierService {
private SoldierDao soldierDao = new SoldierDaoImpl();
@Override
public List<Soldier> getSoldierList() {
return soldierDao.selectSoldierList();
}
}
SoldierServlet
package com.softeem.servlet;
import com.softeem.bean.Soldier;
import com.softeem.service.SoldierService;
import com.softeem.service.impl.SoldierServiceImpl;
import com.softeem.utils.ModelBaseServlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/SoldierServlet")
public class SoldierServlet extends ModelBaseServlet {
protected void showList(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建业务层对象:soldierService
SoldierService soldierService = new SoldierServiceImpl() ;
// 1.调用Service方法获取集合数据
List<Soldier> soldierList = soldierService.getSoldierList();
for (Soldier soldier : soldierList) {
System.out.println("soldier = " + soldier);
}
// 2.将集合数据存入请求域
req.setAttribute("soldierList" ,soldierList);
// 3.渲染视图(在渲染的过程中,已经包含了转发)
super.processTemplate("list" ,req,resp);
}
}
list.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table border="1">
<tr>
<th>士兵编号</th>
<th>士兵姓名</th>
<th>士兵武器</th>
<th>士兵性别</th>
<th>士兵年龄</th>
<th>士兵生日</th>
</tr>
<tr th:each="soldier : ${soldierList}">
<td th:text="${soldier.soldierId}"></td>
<td th:text="${soldier.soldierName}"></td>
<td th:text="${soldier.soldierWeapon}"></td>
<td th:text="${soldier.soldierSex}"></td>
<td th:text="${soldier.soldierAge}"></td>
<td th:text="${soldier.soldierBirthday}"></td>
</tr>
</table>
</body>
</html>
BaseDao中的4个方法.开始驼峰转换,否则不法获取数据
/**
* 获取所有对象
*
* @param sql
* @param params
* @return
*/
public List<T> getBeanList(Connection conn, String sql, Object... params) {
List<T> list = null;
try {
//开启下划线->驼峰转换所用
BeanProcessor bean = new GenerousBeanProcessor();
RowProcessor processor = new BasicRowProcessor(bean);
list = queryRunner.query(conn, sql, new BeanListHandler<T>(type,processor), params);
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
/**
* 获取所有对象
*
* @param sql
* @param params
* @return
*/
public List<T> getBeanList( String sql, Object... params) {
List<T> list = null;
try {
//开启下划线->驼峰转换所用
BeanProcessor bean = new GenerousBeanProcessor();
RowProcessor processor = new BasicRowProcessor(bean);
list = queryRunner.query( sql, new BeanListHandler<T>(type,processor), params);
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
/**
* 获取一个对象
*
* @param sql
* @param params
* @return
*/
public T getBean(Connection conn,String sql, Object... params) {
T t = null;
try { //type == String.class
//开启下划线->驼峰转换所用
BeanProcessor bean = new GenerousBeanProcessor();
RowProcessor processor = new BasicRowProcessor(bean);
t = queryRunner.query(conn, sql, new BeanHandler<T>(type,processor), params);
} catch (SQLException e) {
e.printStackTrace();
}
return t;
}
/**
* 获取一个对象
*
* @param sql
* @param params
* @return
*/
public T getBean(String sql, Object... params) {
T t = null;
try { //type == String.class
//开启下划线->驼峰转换所用
BeanProcessor bean = new GenerousBeanProcessor();
RowProcessor processor = new BasicRowProcessor(bean);
t = queryRunner.query( sql, new BeanHandler<T>(type,processor), params);
} catch (SQLException e) {
e.printStackTrace();
}
return t;
}
前往修改信息的表单页面
两种不同的传参方法,语法不同.但是效果是一样的
<a th:href="@{SoldierServlet(soldierId=${soldier.soldierId},method=toEditPage)}">编辑</a>
<a th:href="@{'SoldierServlet?soldierId='+${soldier.soldierId}+'&method=toEditPage'}">编辑</a>
SoldierDao接口增加方法
Soldier findById(String soldierId);
SoldierDaoImpl实现类增加方法
@Override
public Soldier findById(String soldierId) {
return super.getBean("select * from t_soldier where soldier_id = ?" , soldierId);
}
SoldierService接口增加方法
Soldier getSoldierById(String soldierId);
SoldierServiceImpl实现类增加方法
@Override
public Soldier getSoldierById(String soldierId) {
return soldierDao.findById(soldierId);
}
SoldierServlet类添加方法
protected void toEditPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1获取客户端提交上来的士兵主键id
String soldierId = req.getParameter("soldierId");
//2业务层对象根据主键id去查询此士兵的信息,返回一个士兵对象
SoldierService soldierService = new SoldierServiceImpl();
Soldier soldier = soldierService.getSoldierById(soldierId);
//把soldier对象保存到req请求域对象中,传到网页中去
req.setAttribute("soldier" , soldier);
//跳传到edit-page网页,并且携带了soldier对象
super.processTemplate("edit-page" ,req,resp);
}
日期这儿我们使用一个js控制..不要用户自己输入日期.用户输入的日期可能不符合我们的格式要求
<base th:href="@{/}">
<!-- 引入日期控件的js文件 -->
<script language="javascript" type="text/javascript" th:src="@{My97DatePicker/WdatePicker.js}"></script>
input元素使用日期控件
<tr>
<td>士兵生日:</td>
<td><input type="text" name="soldierBirthday" th:value="${soldier.soldierBirthday}" onclick="WdatePicker({el:this,dateFmt:'yyyy-MM-dd'})"></td>
</tr>
SoldierDao接口增加方法
void updateById(Soldier soldier);
SoldierDaoImpl实现类增加方法
@Override
public void updateById(Soldier soldier) {
String sql = "update t_soldier set soldier_name=?,soldier_weapon=?,soldier_sex=?,soldier_age=?,soldier_birthday=? where soldier_id=?";
super.update(sql,soldier.getSoldierName(),soldier.getSoldierWeapon(),soldier.getSoldierSex(),
soldier.getSoldierAge(),soldier.getSoldierBirthday(),soldier.getSoldierId());
}
SoldierService接口增加方法
void updateSoldier(Soldier soldier);
SoldierServiceImpl实现类增加方法
@Override
public void updateSoldier(Soldier soldier) {
soldierDao.updateById(soldier);
}
SoldierServlet类添加方法
protected void updateSoldier(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, ParseException {
// 1.获取请求参数
String soldierId = req.getParameter("soldierId");
String soldierName = req.getParameter("soldierName");
String soldierWeapon = req.getParameter("soldierWeapon");
String soldierSex = req.getParameter("soldierSex");
String soldierAge = req.getParameter("soldierAge");
String soldierBirthday = req.getParameter("soldierBirthday");
// 2.封装对象
Soldier soldier = new Soldier();
soldier.setSoldierId(Integer.parseInt(soldierId));
soldier.setSoldierName(soldierName);
soldier.setSoldierWeapon(soldierWeapon);
soldier.setSoldierSex(soldierSex);
if(soldierAge!=null && !soldierAge.equals("")){
soldier.setSoldierAge(Integer.parseInt(soldierAge));
}
//非null and 非空串 才能执行if里面的代码
if(soldierBirthday!=null && !soldierBirthday.equals("")){
//创建一个日期格式解析器对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//将字符串转换成一个日期对象: date
Date date = sdf.parse(soldierBirthday);
//把util包下的date对象转换成了sql包下的date对象
soldier.setSoldierBirthday(new java.sql.Date(date.getTime()));
}
//创建业务层对象:soldierService
SoldierService soldierService = new SoldierServiceImpl();
// 3.调用Service方法执行更新
soldierService.updateSoldier(soldier);
//不要直接跳转到list网页,因为你没有传递过去.list网页里面什么都不会显示,无意义
//super.processTemplate("list" ,req ,resp);
//这样调用showList方法.刷新网页时.会出现表单重复提交的问题
//this.showList(req,resp);//调用showList,此方法会跳转到list网页并传递数据
//如果想解决表单重复提交,我们可以使用重定向跳转的方式来解决此问题
//req.getContextPath() 此方法可获取当前工程路径
resp.sendRedirect(req.getContextPath() + "/SoldierServlet?method=showList");
//注意前面不要加[/]斜杠,如果加了[/]斜杠.就变成了http://localhost:8080/SoldierServlet?method=showList
}
删除功能
SoldierDao接口增加方法
void deleteById(String soldierId);
SoldierDaoImpl实现类增加方法
@Override
public void deleteById(String soldierId) {
super.update("delete from t_soldier where soldier_id=?" , soldierId);
}
SoldierService接口增加方法
void remove(String soldierId);
SoldierServiceImpl实现类增加方法
@Override
public void remove(String soldierId) {
soldierDao.deleteById(soldierId);
}
SoldierServlet类添加方法
protected void remove(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.获取请求参数
String soldierId = req.getParameter("soldierId");
//2.调用业务层方法
SoldierService soldierService = new SoldierServiceImpl();
soldierService.remove(soldierId);
//req.getContextPath() 此方法可获取当前工程路径
System.out.println("req.getContextPath() = " + req.getContextPath());
//3.跳转到list网页
resp.sendRedirect(req.getContextPath() + "/SoldierServlet?method=showList");
}
list.html网页部分
<a href="javascript:void(0)" th:onclick="'mydelete('+${soldier.soldierId}+')'">删除</a>
<script>
function mydelete(id){
if(window.confirm("你确定删除此数据吗?")){
window.location.href = "SoldierServlet?method=remove&soldierId="+id;
}
}
</script>
添加成能
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<base th:href="@{/}">
<!-- 引入日期控件的js文件 -->
<script type="text/javascript" th:src="@{My97DatePicker/WdatePicker.js}"></script>
</head>
<body>
<form th:action="@{SoldierServlet}" method="post">
<input type="hidden" name="method" value="saveSoldier" />
<table border="1">
<tr>
<td>士兵姓名:</td>
<td><input type="text" name="soldierName"></td>
</tr>
<tr>
<td>士兵武器:</td>
<td><input type="text" name="soldierWeapon"></td>
</tr>
<tr>
<td>士兵性别:</td>
<td><input type="text" name="soldierSex"></td>
</tr>
<tr>
<td>士兵年龄:</td>
<td><input type="text" name="soldierAge"></td>
</tr>
<tr>
<td>士兵生日:</td>
<td><input type="text" name="soldierBirthday" onclick="WdatePicker({el:this,dateFmt:'yyyy-MM-dd'})"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="添加">
</td>
</tr>
</table>
</form>
</body>
</html>
SoldierDao接口添加方法
void save(Soldier soldier);
SoldierDaoImpl实现类添加方法
@Override
public void save(Soldier soldier) {
String sql = "insert into t_soldier values(null,?,?,?,?,?)";
super.update(sql,soldier.getSoldierName(),soldier.getSoldierWeapon(),soldier.getSoldierSex(),soldier.getSoldierAge(),soldier.getSoldierBirthday());
}
SoldierService接口增加方法
void save(Soldier soldier);
SoldierServiceImpl实现类增加方法
@Override
public void save(Soldier soldier) {
soldierDao.save(soldier);
}
SoldierServlet类添加方法
protected void saveSoldier(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, ParseException {
// 1.获取请求参数
String soldierName = req.getParameter("soldierName");
String soldierWeapon = req.getParameter("soldierWeapon");
String soldierSex = req.getParameter("soldierSex");
String soldierAge = req.getParameter("soldierAge");
String soldierBirthday = req.getParameter("soldierBirthday");
// 2.封装对象
Soldier soldier = new Soldier();
soldier.setSoldierName(soldierName);
soldier.setSoldierWeapon(soldierWeapon);
soldier.setSoldierSex(soldierSex);
if (soldierAge != null && !soldierAge.equals("")) {
soldier.setSoldierAge(Integer.parseInt(soldierAge));
}
//非null and 非空串 才能执行if里面的代码
if (soldierBirthday != null && !soldierBirthday.equals("")) {
//创建一个日期格式解析器对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//将字符串转换成一个日期对象: date
Date date = sdf.parse(soldierBirthday);
//把util包下的date对象转换成了sql包下的date对象
soldier.setSoldierBirthday(new java.sql.Date(date.getTime()));
}
//创建业务层对象:soldierService
SoldierService soldierService = new SoldierServiceImpl();
//保存soldier对象到数据库
soldierService.save(soldier);
//这样操作会出现表单重复提交问题,不要这样操作
//this.showList(req,resp);
//重定向的方式.可以很好的解决表单重复提交的问题
resp.sendRedirect(req.getContextPath()+"/SoldierServlet?method=showList");
}