Javajava怎么在控制台输出代码可以写到Java web里吗?

1,JavaWeb后端经过前面的学习,现在终于可以正式进入到后端的学习当中,不过,我们还是需要再系统地讲解一下HTTP通信基础知识,它是我们学习JavaWeb的基础知识,我们之前已经学习过TCP通信,而HTTP实际上是基于TCP协议之上的应用层协议,因此理解它并不难理解。打好基础是关键!为什么要去花费时间来讲解计算机网络基础,我们学习一门技术,如果仅仅是知道如何使用却不知道其原理,那么就成了彻头彻尾的“码农”,只知道搬运代码实现功能,却不知道这行代码的执行流程,在遇到一些问题的时候就不知道如何解决,无论是知识层面还是应用层面都得不到提升。无论怎么样,我们都要明确,我们学习JavaWeb的最终目的是为了搭建一个网站,并且让用户能访问我们的网站并在我们的网站上做一些事情。2,计算机网络基础在计算机网络(谢希仁 第七版 第264页)中,是这样描述万维网的:万维网(World Wide Web)并非是某种特殊的计算机网络,
万维网是一个大规模的联机式信息储藏所,英文简称Web,万维网用链接的方法,
能够非常方便地从互联网上的一个站点访问另一个站点,
从而主动地按需求获取丰富的信息。
这句话说的非常官方,但是也蕴藏着许多的信息,首先它指明,我们的互联网上存在许许多多的服务器,而我们通过访问这些服务器就能快速获取服务器为我们提供的信息(比如打开百度就能展示搜索、打开小破站能刷视频、打开微博能查看实时热点)而这些服务器就是由不同的公司在运营。其次,我们通过浏览器,只需要输入对应的网址或是点击页面中的一个链接,就能够快速地跳转到另一个页面,从而按我们的意愿来访问服务器。而书中是这样描述万维网的工作方式:万维网以客户服务器的方式工作,浏览器就是安装在用户主机上的万维网客户程序,
万维网文档所驻留的主机则运行服务器程序,因此这台主机也称为万维网服务器。
客户程序向服务器程序发出请求,服务器程序向客户程序送回客户所要的万维网文档,
在一个客户程序主窗口上显示出的万维网文档称为页面。
上面提到的客户程序其实就是我们电脑上安装的浏览器,而服务端就是我们即将要去学习的Web服务器,也就是说,我们要明白如何搭建一个Web服务器并向用户发送我们提供的Web页面,在浏览器中显示的,一般就是HTML文档被解析后的样子。那么,我们的服务器可能不止一个页面,可能会有很多个页面,那么客户端如何知道该去访问哪个服务器的哪个页面呢?这个时候就需要用到URL统一资源定位符。互联网上所有的资源,都有一个唯一确定的URL,比如http://www.baidu.comURL的格式为:<协议>://<主机>:<端口>/<路径>
协议是指采用什么协议来访问服务器,不同的协议决定了服务器返回信息的格式,我们一般使用HTTP协议。
主机可以是一个域名,也可以是一个IP地址(实际上域名最后会被解析为IP地址进行访问)
端口是当前服务器上Web应用程序开启的端口,我们前面学习TCP通信的时候已经介绍过了,HTTP协议默认使用80端口,因此有时候可以省略。
路径就是我们希望去访问此服务器上的某个文件,不同的路径代表访问不同的资源。
3,认识Tomcat服务器Tomcat(汤姆猫)就是一个典型的Web应用服务器软件,通过运行Tomcat服务器,我们就可以快速部署我们的Web项目,并交由Tomcat进行管理,我们只需要直接通过浏览器访问我们的项目即可。那么首先,我们需要进行一个简单的环境搭建,我们需要在Tomcat官网下载最新的Tomcat服务端程序:https://tomcat.apache.org/download-10.cgi(下载速度可能有点慢)下载:64-bit Windows zip
下载完成后,解压,并放入桌面,接下来需要配置一下环境变量,打开高级系统设置,打开环境变量,添加一个新的系统变量,变量名称为JRE_HOME,填写JDK的安装目录+/jre,比如Zulujdk默认就是:C:\Program Files\Zulu\zulu-8\jre设置完成后,我们进入tomcat文件夹bin目录下,并在当前位置打开CMD窗口,将startup.sh拖入窗口按回车运行,如果环境变量配置有误,会提示,若没问题,服务器则正常启动。如果出现乱码,说明编码格式配置有问题,我们修改一下服务器的配置文件,打开conf文件夹,找到logging.properties文件,这就是日志的配置文件(我们在前面已经给大家讲解过了)将ConsoleHandler的默认编码格式修改为GBK编码格式:java.util.logging.ConsoleHandler.encoding = GBK
现在重新启动服务器,就可以正常显示中文了。服务器启动成功之后,不要关闭,我们打开浏览器,在浏览器中访问:http://localhost:8080/,Tomcat服务器默认是使用8080端口(可以在配置文件中修改),访问成功说明我们的Tomcat环境已经部署成功了。整个Tomcat目录下,我们已经认识了bin目录(所有可执行文件,包括启动和关闭服务器的脚本)以及conf目录(服务器配置文件目录),那么我们接着来看其他的文件夹:● lib目录:Tomcat服务端运行的一些依赖,不用关心。
● logs目录:所有的日志信息都在这里。
● temp目录:存放运行时产生的一些临时文件,不用关心。
● work目录:工作目录,Tomcat会将jsp文件转换为java文件(我们后面会讲到,这里暂时不提及)
● webapp目录:所有的Web项目都在这里,每个文件夹都是一个Web应用程序:
我们发现,官方已经给我们预设了一些项目了,访问后默认使用的项目为ROOT项目,也就是我们默认打开的网站。我们也可以访问example项目,只需要在后面填写路径即可:http://localhost:8080/examples/,或是docs项目(这个是Tomcat的一些文档)http://localhost:8080/docs/Tomcat还自带管理页面,我们打开:http://localhost:8080/manager,提示需要用户名和密码,由于不知道是什么,我们先点击取消,页面中出现如下内容:You are not authorized to view this page. If you have not changed any configuration files, please examine the file conf/tomcat-users.xml in your installation. That file must contain the credentials to let you use this webapp.
For example, to add the manager-gui role to a user named tomcat with a password of s3cret, add the following to the config file listed above.
Note that for Tomcat 7 onwards, the roles required to use the manager application were changed from the single manager role to the following four roles. You will need to assign the role(s) required for the functionality you wish to access.
● manager-gui - allows access to the HTML GUI and the status pages
● manager-script - allows access to the text interface and the status pages
● manager-jmx - allows access to the JMX proxy and the status pages
● manager-status - allows access to the status pages only
The HTML interface is protected against CSRF but the text and JMX interfaces are not. To maintain the CSRF protection:
● Users with the manager-gui role should not be granted either the manager-script or manager-jmx roles.
● If the text or jmx interfaces are accessed through a browser (e.g. for testing since these interfaces are intended for tools not humans) then the browser must be closed afterwards to terminate the session.
For more information - please see the Manager App How-To.
<role rolename="manager-gui"/>
<user username="tomcat" password="s3cret" roles="manager-gui"/>
现在我们按照上面的提示,去配置文件中进行修改:
<role rolename="manager-gui"/>
<user username="admin" password="admin" roles="manager-gui"/>
现在再次打开管理页面,已经可以成功使用此用户进行登陆了。登录后,展示给我们的是一个图形化界面,我们可以快速预览当前服务器的一些信息,包括已经在运行的Web应用程序,甚至还可以查看当前的Web应用程序有没有出现内存泄露。同样的,还有一个虚拟主机管理页面,用于一台主机搭建多个Web站点,一般情况下使用不到,这里就不做演示了。4,使用Maven创建Web项目引入maven<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
pom文件<?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>com.study</groupId>
<artifactId>javaweb_maven_demo01</artifactId>
<version>1.0-SNAPSHOT</version>
<!--打包方式-->
<packaging>war</packaging>
</project>
5,Servlet前面我们已经完成了基本的环境搭建,那么现在我们就可以开始来了解我们的第一个重要类——Servlet。它是Java EE的一个标准,大部分的Web服务器都支持此标准,包括Tomcat,就像之前的JDBC一样,由官方定义了一系列接口,而具体实现由我们来编写,最后交给Web服务器(如Tomcat)来运行我们编写的Servlet。那么,它能做什么呢?我们可以通过实现Servlet来进行动态网页响应,使用Servlet,不再是直接由Tomcat服务器发送我们编写好的静态网页内容(HTML文件),而是由我们通过Java代码进行动态拼接的结果,它能够很好地实现动态网页的返回。当然,Servlet并不是专用于HTTP协议通信,也可以用于其他的通信,但是一般都是用于HTTP。5.1 快速入门引入maven <dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
创建ServletDemo类并像控制台输出一句话package com.study;
import javax.servlet.*;
import java.io.IOException;
public class ServletDemo implements Servlet {
public void init(ServletConfig config) throws ServletException {
}
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("111111");
}
public String getServletInfo() {
return null;
}
public void destroy() {
}
}
修改xml
<web-app>
<servlet>
<servlet-name>demo1</servlet-name>
<servlet-class>com.study.ServletDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
</web-app>
启动tomcat通过浏览器访问程序http://localhost:8080/javaweb_maven_demo01_war/demo15.2 Servlet执行流程5.3 Servlet生命周期package com.study;
import javax.servlet.*;
import java.io.IOException;
public class ServletDemo2 implements Servlet {
/**
* servlet被创建时执行
* @param config
* @throws ServletException
*/
public void init(ServletConfig config) throws ServletException {
System.out.println("init...");
}
/**
* servlet被调用时执行
* @param req
* @param res
* @throws ServletException
* @throws IOException
*/
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("service...");
}
/**
* servlet被销毁时执行
*/
public void destroy() {
System.out.println("destroy...");
}
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
}
5.4 Servlet体系结构package com.study;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo3 extends HttpServlet {
/**
* 处理get请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet");
super.doGet(req, resp);
}
/**
* 处理post请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost");
super.doPost(req, resp);
}
/**
* 处理put请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPut");
super.doPut(req, resp);
}
/**
* 处理Delete请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doDelete");
super.doDelete(req, resp);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/javaweb_maven_demo01_war/demo3" method="post">
<input name="username">
<input type="submit">
</form>
</body>
</html>
6,Request(请求)和Response(响应)6.1 Request继承体系6.2 Request获取请求数据6.2.1 获取请求行package com.study;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo3 extends HttpServlet {
/**
* 处理get请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
System.out.println("getMethod:"+req.getMethod());
System.out.println("getContextPath:"+req.getContextPath());
System.out.println("getContextPath:"+req.getContextPath());
System.out.println("getRequestURI:"+req.getRequestURI());
System.out.println("getQueryString(:"+req.getQueryString());
//
System.out.println("doGet");
//
String name = req.getParameter("name");
//
//
resp.setHeader("content-type","text/html;charset=utf-8");
//
resp.getWriter().write("<h1>"+ name +"欢迎你</h1>");
}
/**
* 处理post请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost");
//
super.doPost(req, resp);
}
/**
* 处理put请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPut");
//
super.doPut(req, resp);
}
/**
* 处理Delete请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doDelete");
//
super.doDelete(req, resp);
}
}
6.2.2 获取请求头@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
System.out.println("getHeader:"+req.getHeader("Accept-Language"));
//
System.out.println("doGet");
//
String name = req.getParameter("name");
//
//
resp.setHeader("content-type","text/html;charset=utf-8");
//
resp.getWriter().write("<h1>"+ name +"欢迎你</h1>");
}
6.2.3 获取请求体 /**
* 处理post请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost");
//获取请求体
BufferedReader br = req.getReader();
String line = br.readLine();
System.out.println(line);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/javaweb_maven_demo01_war/demo3" method="post">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit">
</form>
</body>
</html>
6.3 Request通用方式获取请求数据6.3.1 get请求接收数据6.3.1.1 获取所有参数的map集合@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
//获取所有参数的map集合
Map<String, String[]> map =
req.getParameterMap();
for (String key : map.keySet()) {
System.out.println(key+":");
String[] values = map.get(key);
for (String value : values) {
System.out.print(value+" ");
}
System.out.println();
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/javaweb_maven_demo01_war/demo3" method="get">
<input type="text" name="username">
<input type="password" name="password">
<input type="checkbox" name="hobby" value="1">游泳
<input type="checkbox" name="hobby" value="2">爬山
<input type="submit">
</form>
</body>
</html>
6.3.1.2 更具key获取参数值,数组@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
//更具key获取参数值,数组
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/javaweb_maven_demo01_war/demo3" method="get">
<input type="text" name="username">
<input type="password" name="password">
<input type="checkbox" name="hobby" value="1">游泳
<input type="checkbox" name="hobby" value="2">爬山
<input type="submit">
</form>
</body>
</html>
6.3.1.3 更具key获取单个参数值@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
//更具key获取单个参数值
String password = req.getParameter("password");
System.out.println(password);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/javaweb_maven_demo01_war/demo3" method="get">
<input type="text" name="username">
<input type="password" name="password">
<input type="checkbox" name="hobby" value="1">游泳
<input type="checkbox" name="hobby" value="2">爬山
<input type="submit">
</form>
</body>
</html>
6.3.2 post请求接收数据 @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取所有参数的map集合
Map<String, String[]> map =
req.getParameterMap();
for (String key : map.keySet()) {
System.out.println(key+":");
String[] values = map.get(key);
for (String value : values) {
System.out.print(value+" ");
}
System.out.println();
}
System.out.println("==================");
//更具key获取参数值,数组
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
System.out.println("==================");
//更具key获取单个参数值
String password = req.getParameter("password");
System.out.println(password);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/javaweb_maven_demo01_war/demo3" method="post">
<input type="text" name="username">
<input type="password" name="password">
<input type="checkbox" name="hobby" value="1">游泳
<input type="checkbox" name="hobby" value="2">爬山
<input type="submit">
</form>
</body>
</html>
6.4 Request请求转发package com.study;
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.util.Map;
public class ServletDemo4 extends HttpServlet {
/**
* 处理get请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ServletDemo4");
Object iphone = req.getAttribute("iphone");
System.out.println(iphone.toString());
}
/**
* 处理post请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
package com.study;
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 ServletDemo5 extends HttpServlet {
/**
* 处理get请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ServletDemo5");
req.setAttribute("iphone","18110229299");
//请求转发
req.getRequestDispatcher("/demo4").forward(req,resp);
}
/**
* 处理post请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
6.5 Response设置响应数据和重定向6.5.1 Response设置响应数据6.5.2 Response重定向package com.study.response;
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 ResponseDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ResponseDemo01.....");
//重定向
//设置响应状态码
//
resp.setStatus(302);
//设置响应头
//
resp.setHeader("Location","/javaweb_maven_demo01/resp2");
// 动态获取虚拟目录
String contextPath = req.getContextPath();
//简化写法
resp.sendRedirect(contextPath+"/resp2");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
package com.study.response;
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 ResponseDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ResponseDemo02....");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
6.5.3 Response响应字符数据package com.study.response;
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 ResponseDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置中文编码
resp.setContentType("text/html;charset=utf-8");
PrintWriter writer = resp.getWriter();
//设置头信息
//
resp.setHeader("content-type","text/html");
writer.write("<h1>aaa,张三</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
6.5.4 Response响应字节数据package com.study.response;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
public class ResponseDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1,读取文件
FileInputStream fis =
new FileInputStream("E://Snipaste_2023-01-09_18-46-55.png");
// 2,获取response字节输出流
ServletOutputStream os = resp.getOutputStream();
byte[] buff = new byte[1024];
int len = 0;
while ((len = fis.read(buff)) != -1){
os.write(buff,0,len);
}
fis.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
使用Thymeleaf模板引擎虽然JSP为我们带来了便捷,但是其缺点也是显而易见的,那么有没有一种既能实现模板,又能兼顾前后端分离的模板引擎呢?Thymeleaf(百里香叶)是一个适用于Web和独立环境的现代化服务器端Java模板引擎,官方文档:https://www.thymeleaf.org/documentation.html。(区分 EL表达式 和 Thymeleaf:1、EL表达式只和JSP挂钩,在html中是无法使用的;而thymeleaf是使用的html静态网页。(Thymeleaf是Spring-Boot官方推荐模板引擎)2、要么使用EL + JSP,要么使用thymeleaf + html,两种模式不要混用,鱼和熊掌不可兼得。)那么它和JSP相比,好在哪里呢,我们来看官网给出的例子:
Name Price
Oranges 0.99
我们可以在前端页面中填写占位符,而这些占位符的实际值则由后端进行提供,这样,我们就不用再像JSP那样前后端都写在一起了。那么我们来创建一个例子感受一下,首先还是新建一个项目,注意,在创建时,勾选Thymeleaf依赖。创建好项目后,首先要将pom.xml中关于servlet的依赖替换!!!换成 jakarta.servlet jakarta.servlet-api 5.0.0 provided 首先将项目自带的index.jsp删除首先编写一个前端页面,名称为test.html,注意,是放在resource目录下,在html标签内部添加xmlns:th="http://www.thymeleaf.org"引入Thymeleaf定义的标签属性: Title
接着我们编写一个Servlet作为默认页面:(导入类:org.thymeleaf.context)(将title作为占位符,一会儿会直接将title替换成“我是标题”)(process其实是将页面拿出来进行解析,解析完后将内容发给浏览器)@WebServlet("/index") public class HelloServlet extends HttpServlet { TemplateEngine engine; @Override public void init() throws ServletException { engine = new TemplateEngine(); ClassLoaderTemplateResolver r = new ClassLoaderTemplateResolver(); engine.setTemplateResolver(r); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); context.setVariable("title", "我是标题"); engine.process("test.html", context, resp.getWriter()); } } 我们发现,浏览器得到的页面,就是已经经过模板引擎解析好的页面,而我们的代码依然是后端处理数据,前端展示数据,因此使用Thymeleaf就能够使得当前Web应用程序的前后端划分更加清晰。虽然Thymeleaf在一定程度上分离了前后端,但是其依然是在后台渲染HTML页面并发送给前端,并不是真正意义上的前后端分离。0、惯用配置HelloServlet@WebServlet("/index") public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); context.setVariable("list", Arrays.asList("伞兵一号的故事", "倒一杯卡布奇诺", "玩游戏要啸着玩", "十七张牌前的电脑屏幕")); ThymeleafUtil.getEngine().process("test.html", context, resp.getWriter()); } } ThymeleafUtilpublic class ThymeleafUtil { private static final TemplateEngine engine; static { engine = new TemplateEngine(); ClassLoaderTemplateResolver r = new ClassLoaderTemplateResolver(); engine.setTemplateResolver(r); } public static TemplateEngine getEngine() { return engine; } } 1、Thymeleaf语法基础那么,如何使用Thymeleaf呢?首先我们看看后端部分,我们需要通过TemplateEngine对象来将模板文件渲染为最终的HTML页面:TemplateEngine engine; // 模版引擎 @Override public void init() throws ServletException { engine = new TemplateEngine(); //设定模板解析器决定了从哪里获取模板文件,这里直接使用ClassLoaderTemplateResolver表示加载内部资源文件 ClassLoaderTemplateResolver r = new ClassLoaderTemplateResolver(); engine.setTemplateResolver(r); } 由于此对象只需要创建一次,之后就可以一直使用了。接着我们来看如何使用模板引擎进行解析:@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //创建上下文,上下文中包含了所有需要替换到模板中的内容 Context context = new Context(); context.setVariable("title", "

我是标题

"); //通过此方法就可以直接解析模板并返回响应 engine.process("test.html", context, resp.getWriter()); } 操作非常简单,只需要简单几步配置就可以实现模板的解析。接下来我们就可以在前端页面中通过上下文提供的内容,来将Java代码中的数据解析到前端页面。接着我们来了解Thymeleaf如何为普通的标签添加内容,比如我们示例中编写的:
我们使用了th:text来为当前标签指定内部文本,注意任何内容都会变成普通文本,即使传入了一个HTML代码,如果我希望向内部添加一个HTML文本呢?我们可以使用th:utext属性:
并且,传入的title属性,不仅仅只是一个字符串的值,而是一个字符串的引用,我们可以直接通过此引用调用相关的方法:
这样看来,Thymeleaf既能保持JSP为我们带来的便捷,也能兼顾前后端代码的界限划分。除了替换文本,它还支持替换一个元素的任意属性,我们发现,th:能够拼接几乎所有的属性,一旦使用th:属性名称,那么属性的值就可以通过后端提供了,比如我们现在想替换一个图片的链接:@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); context.setVariable("url", "http://n.sinaimg.cn/sinakd20121/600/w1920h1080/20210727/a700-adf8480ff24057e04527bdfea789e788.jpg"); context.setVariable("alt", "图片就是加载不出来啊"); engine.process("test.html", context, resp.getWriter()); } Title 现在访问我们的页面,就可以看到替换后的结果了。Thymeleaf还可以进行一些算术运算,几乎Java中的运算它都可以支持:
同样的,它还支持三元运算:
多个属性也可以通过+进行拼接,就像Java中的字符串拼接一样,这里要注意一下,字符串不能直接写,要添加单引号:
2、Thymeleaf流程控制语法除了一些基本的操作,我们还可以使用Thymeleaf来处理流程控制语句,当然,不是直接编写Java代码的形式,而是添加一个属性即可。首先我们来看if判断语句,如果if条件满足,则此标签留下,若if条件不满足,则此标签自动被移除:@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); context.setVariable("eval", true); engine.process("test.html", context, resp.getWriter()); }
我是判断条件标签
th:if会根据其中传入的值或是条件表达式的结果进行判断,只有满足的情况下,才会显示此标签,具体的判断规则如下:th:if还有一个相反的属性th:unless,效果完全相反,这里就不演示了。我们接着来看多分支条件判断,我们可以使用th:switch属性来实现:
我是1
我是2
我是3
只不过没有Default属性,但是我们可以使用th:case="*"来代替:
我是Default
最后我们再来看看,它如何实现遍历,假如我们有一个存放书籍信息的List需要显示,那么如何快速生成一个列表呢?我们可以使用th:each来进行遍历操作:@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); context.setVariable("list", Arrays.asList("伞兵一号的故事", "倒一杯卡布奇诺", "玩游戏要啸着玩", "十七张牌前的电脑屏幕")); engine.process("test.html", context, resp.getWriter()); }
th:each中需要填写 “单个元素名称 : ${列表}”,这样,所有的列表项都可以使用遍历的单个元素,只要使用了th:each,都会被循环添加。因此最后生成的结果为:
  • 《伞兵一号的故事》
  • 《倒一杯卡布奇诺》
  • 《玩游戏要啸着玩》
  • 《十七张牌前的电脑屏幕》
我们还可以获取当前循环的迭代状态,只需要在最后添加iterStat即可,从中可以获取很多信息,比如当前的顺序:
状态变量在th:each属性中定义,并包含以下数据:当前迭代索引,以0开头。这是index属性。当前迭代索引,以1开头。这是count属性。迭代变量中的元素总量。这是size属性。每个迭代的迭代变量。这是current属性。当前迭代是偶数还是奇数。这些是even/odd布尔属性。当前迭代是否是第一个迭代。这是first布尔属性。当前迭代是否是最后一个迭代。这是last布尔属性。通过了解了流程控制语法,现在我们就可以很轻松地使用Thymeleaf来快速替换页面中的内容了。3、Thymeleaf模板布局在某些网页中,我们会发现,整个网站的页面,除了中间部分的内容会随着我们的页面跳转而变化外,有些部分是一直保持一个状态的,比如打开小破站,我们翻动评论或是切换视频分P的时候,变化的仅仅是对应区域的内容,实际上,其他地方的内容会无论内部页面如何跳转,都不会改变。Thymeleaf就可以轻松实现这样的操作,我们只需要将不会改变的地方设定为模板布局,并在不同的页面中插入这些模板布局,就无需每个页面都去编写同样的内容了。现在我们来创建两个页面: Title

我是标题内容,每个页面都有


test2.html Title

我是标题内容,每个页面都有


这个页面的样子是这样的
接着将模板引擎写成工具类的形式:(然后将HelloServlet中的init以及上面的engine删除)public class ThymeleafUtil { private static final TemplateEngine engine; static { engine = new TemplateEngine(); ClassLoaderTemplateResolver r = new ClassLoaderTemplateResolver(); engine.setTemplateResolver(r); } public static TemplateEngine getEngine() { return engine; } } @WebServlet("/index2") public class HelloServlet2 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); ThymeleafUtil.getEngine().process("test2.html", context, resp.getWriter()); } } 现在就有两个Servlet分别对应两个页面了,但是这两个页面实际上是存在重复内容的,我们要做的就是将这些重复内容提取出来。我们单独编写一个head.html来存放重复部分:(th:fragment 表示这是一个可以用来替换的模版)

我是标题内容,每个页面都有


现在,我们就可以直接将页面中的内容快速替换:(也就是说只需要用
这样一句话即可替换之前的)
我们可以使用th:insert和th:replace和th:include这三种方法来进行页面内容替换,那么th:insert和th:replace(和th:include,自3.0年以来不推荐)有什么区别?th:insert最简单:它只会插入指定的片段作为标签的主体。 (把所有东西塞到这个div里面,也就是说相比于replace的效果外面多了一层div)th:replace实际上将标签直接替换为指定的片段。th:include和th:insert相似,但它没有插入片段,而是只插入此片段的内容。你以为这样就完了吗?它还支持参数传递,比如我们现在希望插入二级标题,并且由我们的子页面决定(也就是说在每个页面中不一样)

我是标题内容,每个页面都有

我是二级标题


稍加修改,就像JS那样添加一个参数名称:

我是标题内容,每个页面都有


现在直接在替换位置添加一个参数即可:
这样,不同的页面还有着各自的二级标题。探讨Tomcat类加载机制有关JavaWeb的内容,我们就聊到这里,在最后,我们还是来看一下Tomcat到底是如何加载和运行我们的Web应用程序的。Tomcat服务器既然要同时运行多个Web应用程序,那么就必须要实现不同应用程序之间的隔离,也就是说,Tomcat需要分别去加载不同应用程序的类以及依赖,还必须保证应用程序之间的类无法相互访问,而传统的类加载机制无法做到这一点,同时每个应用程序都有自己的依赖,如果两个应用程序使用了同一个版本的同一个依赖,那么还有必要去重新加载吗,带着诸多问题,Tomcat服务器编写了一套自己的类加载机制。首先我们要知道,Tomcat本身也是一个Java程序,它要做的是去动态加载我们编写的Web应用程序中的类,而要解决以上提到的一些问题,就出现了几个新的类加载器,我们来看看各个加载器的不同之处:Common ClassLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Web应用程序访问。Catalina ClassLoader:Tomcat容器私有的类加载器,加载路径中的class对于Web应用程序不可见。Shared ClassLoader:各个Web应用程序共享的类加载器,加载路径中的class对于所有Web应用程序可见,但是对于Tomcat容器不可见。Webapp ClassLoader:各个Web应用程序私有的类加载器,加载路径中的class只对当前Web应用程序可见,每个Web应用程序都有一个自己的类加载器,此加载器可能存在多个实例。JasperLoader:JSP类加载器,每个JSP文件都有一个自己的类加载器,也就是说,此加载器可能会存在多个实例。通过这样进行划分,就很好地解决了我们上面所提到的问题,但是我们发现,这样的类加载机制,破坏了JDK的双亲委派机制(在JavaSE阶段讲解过),比如Webapp ClassLoader,它只加载自己的class文件,它没有将类交给父类加载器进行加载,也就是说,我们可以随意创建和JDK同包同名的类,岂不是就出问题了?难道Tomcat的开发团队没有考虑到这个问题吗?实际上,WebAppClassLoader的加载机制是这样的:WebAppClassLoader 加载类的时候,绕开了 AppClassLoader,直接先使用 ExtClassLoader 来加载类。这样的话,如果定义了同包同名的类,就不会被加载,而如果是自己定义 的类,由于该类并不是JDK内部或是扩展类,所有不会被加载,而是再次回到WebAppClassLoader进行加载,如果还失败,再使用AppClassloader进行加载。实战:编写图书管理系统图书管理系统需要再次迎来升级,现在,我们可以直接访问网站来操作图书,这里我们给大家提供一个前端模板直接编写,省去编写前端的时间。本次实战使用到的框架:Servlet+Mybatis+Thymeleaf(一)总体设计分析注意在编写的时候,为了使得整体的代码简洁高效,我们严格遵守三层架构模式:就是说,表示层(Servlet)只做UI,包括接受请求和响应,给模版添加上下文,以及进行页面的解析,最后响应给浏览器;业务逻辑层才是用于进行数据处理的地方,表示层需要向逻辑层索要数据,才能将数据添加到模版的上下文中;数据访问层一般就是连接数据库,包括增删改查等基本的数据库操作,业务逻辑层如果需要从数据库取数据,就需要向数据访问层请求数据。当然,贯穿三大层次的当属实体类了,我们还需要创建对应的实体类进行数据的封装,以便于在三层架构中进行数据传输。接下来,明确我们要实现的功能,也就是项目需求:图书管理员的登录和退出(只有登录之后才能进行管理页面)图书的列表浏览(包括书籍是否被借出的状态也要进行显示)以及图书的添加和删除学生的列表浏览查看所有的借阅列表,添加借阅信息(二)登录和拦截(我们还是接着用之前的book_manage表)新建一张表admin:(id还要勾选“自动递增”)然后添加一条记录:新建项目:然后勾选Thymeleaf依赖!!(然后将默认自带的index.jsp和HelloServlet和包名都删除)然后首先修改pom.xml中的servlet的依赖 jakarta.servlet jakarta.servlet-api 5.0.0 provided 然后添加lombok的依赖、jdbc、mybatis 4.0.0 com.book BookManagerWeb 1.0-SNAPSHOT BookManagerWeb war UTF-8 1.8 1.8 5.8.2 jakarta.servlet jakarta.servlet-api 5.0.0 provided org.projectlombok lombok 1.18.22 mysql mysql-connector-java 8.0.27 org.mybatis mybatis 3.5.7 org.thymeleaf thymeleaf 3.0.12.RELEASE org.junit.jupiter junit-jupiter-api ${junit.version} test org.junit.jupiter junit-jupiter-engine ${junit.version} test org.apache.maven.plugins maven-war-plugin 3.3.2 将前端模版的login.html复制到resources目录下注意到这个页面还引用了 静态资源(样式之类的)因此,我们再将static这个文件夹复制到webapp目录下(之所以放在resources目录下是因为login.html需要通过thymeleaf来进行动态解析)com.book.utils.ThymeleafUtil比之前的ThymeleafUtil更工具类的写法:public class ThymeleafUtil { private static final TemplateEngine engine; static { engine = new TemplateEngine(); ClassLoaderTemplateResolver r = new ClassLoaderTemplateResolver(); engine.setTemplateResolver(r); } public static void process(String template, IContext context, Writer writer) { engine.process(template, context, writer); } } 创建com.book.servlet.LoginServlet并修改Tomcat配置注意浏览器访问网页是GET请求!!替换login.html中的内容0、加上thymeleaf约束 xmlns:th="http://www.thymeleaf.org"1、去除logo2、更改标题title3、改中文4、表单中: 邮箱 -> 用户名称;并增加name属性5、表单中: password -> 密码;并增加name属性5、表单中: 勾选框 Remember Me -> 记住我;并修改name属性6、“Forgot Password?“ -> “忘记密码?” (但由于我们不写这个功能,直接将链接改成#)7、登录按钮,从a链接变成button;“登录”8、“Don’t have an account?“ -> “没有用户吗?”;9、“Click Here“ -> “注册用户”(由于这里我们仍然不写这个功能,所以还是将链接换成#)10、删掉最下面的Duhh!所在的div11、定义form表单的行为为post,然后我们将行为转给LoginServlet(刚才浏览器直接访问/login是GET请求,现在是POST请求,因此我们写一个doPOST)
com.book.entity.User@Data public class User { int id; String username; String nickname; String password; } com.book.filter.MainFilter@WebFilter(“/*”)表示全部匹配,全部走这个拦截器放行 的情况:请求的是静态资源 or 请求登录页面其他情况下要进行判断,看session中是否有用户观察我们这个项目,静态资源的路径中肯定带有static@WebFilter("/*") public class MainFilter extends HttpFilter { @Override protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException { String url = req.getRequestURL().toString(); if (!url.contains("/static/") && !url.endsWith("login")) { HttpSession session = req.getSession(); User user = (User) session.getAttribute("user"); if (user == null) { res.sendRedirect("login"); return ; } } chain.doFilter(req, res); } } 然后我们发现没有登录的情况下随便输入一个不是login的网址(比如/xxxxxx)就会直接重定向到/login再观察下面可以发现这些静态资源是可以正常的访问到的:resources/mybatis-config.xml创建“数据源”就可以填写这个url com.book.dao.UserMapper接口并注册!!public interface UserMapper { @Select("select * from admin where username = #{username} and password = #{password}") User getUser(@Param("username") String username, @Param("password") String password); } 在mybatis-config.xml中注册: com.book.utils.MybatisUtil小技巧:发现引号里面的mybatis-config.xml变绿了说明就是对了public class MybatisUtil { private static SqlSessionFactory factory; static { try { factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml")); } catch (IOException e) { throw new RuntimeException(e); } } public static SqlSession getSession() { return factory.openSession(true); } } com.book.service.UserService接口从这里开始我们就是写业务逻辑层service一般写法:接口只用来定义(只是定义,不是实现)业务逻辑相关的操作,然后单独再写一个类取实现),然后我们上一层使用只需要导接口即可,不需要关心具体的实现auth方法判断用户是否登录成功由于登录成功之后还要往session中丢东西,因此还要把HttpSession拿过来public interface UserService { boolean auth(String username, String password, HttpSession session); } 接下来就写这个行为的实现com.book.service.impl.UserServiceImplpublic class UserServiceImpl implements UserService { @Override public boolean auth(String username, String password, HttpSession session) { try (SqlSession sqlSession = MybatisUtil.getSession()) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUser(username, password); if (user == null) return false; session.setAttribute("user", user); return true; } } } LoginServlet中使用userService现在用上面这个service来处理数据,注意这里用的是接口!我们在初始化的方法里把它初始化一下,因此Override init方法@WebServlet("/login") public class LoginServlet extends HttpServlet { UserService service; @Override public void init() throws ServletException { service = new UserServiceImpl(); } 然后写doPost:由于如果登录失败了,要在底下显示一串红字,那它怎么知道什么时候显示红字呢?如果是登录失败过去要显示红字,而如果直接过去是不用显示红字的。这个时候我们加个标记即可req.getSession().setAttribute("login-failure", new Object());@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); String remember = req.getParameter("remember-me"); if (service.auth(username, password, req.getSession())) { resp.getWriter().write("Login Success!"); } else { req.getSession().setAttribute("login-failure", new Object()); this.doGet(req, resp); } } 然后对应的在doGet中加个判断,如果要加红字,context中包含东西;还要注意要把它清理掉,因为只有这一次会显示红色的,用户重新刷新页面会重新请求页面,就不会再显示红色了@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); if (req.getSession().getAttribute("login-failure") != null) { context.setVariable("failure", true); req.getSession().removeAttribute("login-failure"); } ThymeleafUtil.process("login.html", context, resp.getWriter()); } 然后在login.html中加一个判断在“请输入用户名和密码进行登录“的后面再加上一个p为错误信息,并将”请输入“的p加上if标签并给“输入不正确“红色

请输入用户名和密码进行登录

您的用户名或密码输入不正确

效果:然后在地址栏重新回车这个地址(注意直接刷新没有用因为会重新提交表单),就发现又变回了“请输入”然后登录成功之后随便输入一个网址就不会被过滤器拦截了(三)管理页面框架搭建将模版的index.html复制到resources目录下com.book.servlet.IndexServlet@WebServlet("/index") public class IndexServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ThymeleafUtil.process("index.html", new Context(), resp.getWriter()); } } 修改LoginServlet中登录成功doPost中登录成功后,重定向到indexif (service.auth(username, password, req.getSession())) { resp.sendRedirect("index"); doGet中如果已经登录成功,重定向到indexif (req.getSession().getAttribute("user") != null) { resp.sendRedirect("index"); return ; } 修改index.html0、加上thymeleaf约束 xmlns:th="http://www.thymeleaf.org"1、修改title2、删除一大堆东西(就是第一行的搜索,购物车这些)3、鼠标移至头像后的列表只留下“退出登录”IndexServlet中修改doGet让首页显示昵称;并修改index.html@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); User user = (User) req.getSession().getAttribute("user"); context.setVariable("nickname", user.getNickname()); ThymeleafUtil.process("index.html", context, resp.getWriter()); }

com.book.servlet.LogoutServlet并创建auth包并修改index.html中退出登录的链接将servlet分类,用户验证类的登录登出单独放一个包auth登出的话,请求即可,不需要带什么参数,所以这里用doGet即可如果退出的话,直接回到登录页面了,注意这个logout也是在过滤器过滤的范围内,也就是说必须登录后才能调logout这个接口,所以说明能进来的肯定是已经验证过的用户@WebServlet("/logout") public class LogoutServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getSession().removeAttribute("user"); resp.sendRedirect("login"); } } 退出登录 验证后成功,且退出登录后在地址栏中输入其他地址会重定向至login且原先的请求状态码为302表示重定向继续清理index.html,左侧栏目只留三个并修改resources/header.html作为模版我们发现header标签里的东西始终是一成不变的,因此,我们创建一个header.html在header.html中添加thymeleaf的依赖并给header.html中加上 th:fragment=“title”然后在index.html中引入模版
resources/students.html首先复制一份index.html然后再替换其中一部分只要将main-content换掉即可换成模版的customers.html中的main-content(用浏览器直接打开customers.html然后f12点击这个部分直接复制代码)然后再更换一下左边栏目的activecom.book.servlet.StudentServlet注意在StudentServlet,虽然使用的是模版,但这个模版最后还是给它塞进去的,所以也是需要nickname这个变量的@WebServlet("/students") public class StudentServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); User user = (User) req.getSession().getAttribute("user"); context.setVariable("nickname", user.getNickname()); ThymeleafUtil.process("students.html", context, resp.getWriter()); } } resources/books.html同上处理方法,这里用的是模版中的orders.html然后再更换一下左边栏目的activecom.book.servlet.BookServlet@WebServlet("/books") public class BookServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); User user = (User) req.getSession().getAttribute("user"); context.setVariable("nickname", user.getNickname()); ThymeleafUtil.process("books.html", context, resp.getWriter()); } } (四)实现借阅信息列表修理index.html1、移除卡片2、仿照卡片的按钮形式

图书借阅列表

3、设计表格4、表格中原有tr只需要保留一行,之后写th:each5、在borrow表中添加一列借阅时间timeentity.Borrow@Data public class Borrow { int id; int book_id; String book_name; Date time; String student_name; int sudent_id; } dao.BookMapper接口(由于一般student比book少,所以先和student内连接再和book内连接)注意这里不是使用内连接!!一共是三条信息,这样才对public interface BookMapper { @Results({ @Result(column = "id", property = "id"), @Result(column = "bid", property = "book_id"), @Result(column = "title", property = "book_name"), @Result(column = "time", property = "time"), @Result(column = "name", property = "student_name"), @Result(column = "sid", property = "student_id"), }) @Select("select * from borrow, student, book where borrow.bid = book.bid and student.sid = borrow.sid") List getBorrowList(); } 注册BookMapper在mybatis-config.xml中将原先的 直接换成,这样就可以直接扫描整个包了 service.BookService接口public interface BookService { List getBorrowList(); } service.impl.BookServiceImplpublic class BookServiceImpl implements BookService { @Override public List getBorrowList() { try (SqlSession sqlSession = MybatisUtil.getSession()) { BookMapper mapper = sqlSession.getMapper(BookMapper.class); return mapper.getBorrowList(); } } } index.html中修改表格数据IndexServlet中使用BookServiceBookService service; @Override public void init() throws ServletException { service = new BookServiceImpl(); } 在doGet中context.setVariable("borrow_list", service.getBorrowList()); 在index.html中获取borrow_list并获取表格数据 #JH2033 我是书名 22/06/2021 我是学生 #1111 index.html中修改归还按钮链接 BookService中写归还接口void returnBook(String id); BookMapper中写归还方法@Delete("delete from borrow where id = #{id}") void deleteBorrow(String id); BookServiceImpl中实现归还接口@Override public void returnBook(String id) { try (SqlSession sqlSession = MybatisUtil.getSession()) { BookMapper mapper = sqlSession.getMapper(BookMapper.class); mapper.deleteBorrow(id); } } servlet.manage.ReturnServlet写归还操作用doGet即可@WebServlet("/return-book") public class ReturnServlet extends HttpServlet { BookService service; @Override public void init() throws ServletException { service = new BookServiceImpl(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String id = req.getParameter("id"); service.returnBook(id); resp.sendRedirect("index"); } } (五)完善借阅操作add-borrow.html还是像之前那样使用index.html进行操作,替换main-content我们使用模版中的form.html然后进行一些删改 修改index.html中按钮链接添加借阅信息 servlet.manage.AddBorrowServletdoGet用来展示页面doPost用来添加借阅信息@WebServlet("/add-borrow") public class AddBorrowServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Context context = new Context(); ThymeleafUtil.process("add-borrow.html", context, resp.getWriter()); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } } entity.Book@Data public class Book { int bid; String title; String desc; double price; } entity.Student@Data public class Student { int sid; String name; String sex; int grade; } dao.StudentMapper接口public interface StudentMapper { @Select("select * from student") List getStudentList(); } BookMapper中“展示书籍列表“方法@Select("select * from book") List getBookList(); BookService定义getActiveBookList等方法过滤List getActiveBookList(); List getStudentList(); BookServiceImpl中实现getActiveBookList和用stream来过滤:如果在set中不存在的,我们才可以让它显示出来@Override public List getActiveBookList() { Set set = new HashSet<>(); this.getBorrowList().forEach(borrow -> set.add(borrow.getBook_id())); try (SqlSession sqlSession = MybatisUtil.getSession()) { BookMapper mapper = sqlSession.getMapper(BookMapper.class); return mapper.getBookList() .stream() .filter(book -> !set.contains(book.getBid())) .collect(Collectors.toList()); } } @Override public List getStudentList() { try (SqlSession sqlSession = MybatisUtil.getSession()) { StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); return mapper.getStudentList(); } } AddBorrowServlet中修改doGetcontext.setVariable("book_list", service.getActiveBookList()); context.setVariable("student_list", service.getStudentList()); add-borrow.html中获取书籍列表学生列表 BookMapper中添加addBorrow方法@Insert("insert into borrow(sid, bid, time) values(#{sid}, #{bid}, Now())") void addBorrow(@Param("sid") int sid, @Param("bid") int bid); BookService中添加addBorrow方法修改borrow表索引中,将bid的 索引类型 改成 UNIQUE不能出现一样的这样子,同一本书就不能被借两次了BookServiceImpl中实现addBorrow方法@Override public void addBorrow(int sid, int bid) { try (SqlSession sqlSession = MybatisUtil.getSession()) { BookMapper mapper = sqlSession.getMapper(BookMapper.class); mapper.addBorrow(sid, bid); } } AddBorrowServlet中修改doPost@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int sid = Integer.parseInt(req.getParameter("student")); int bid = Integer.parseInt(req.getParameter("book")); service.addBorrow(sid, bid); resp.sendRedirect("index"); } (六)书籍列表以及相关操作BookService中添加getBookList方法这个和之间的getActiveBookList的区别就是这个不需要进行过滤由于我们还打算要反映出这本书有没有被借,因此,我们返回类型不采用List,而是用Map,Boolean来反映是否被借BookServieImpl中实现getBookList方法注意HashMap没有顺序,因此我们要用LinkedHashMap@Override public Map getBookList() { Set set = new HashSet<>(); this.getBorrowList().forEach(borrow -> set.add(borrow.getBook_id())); try (SqlSession sqlSession = MybatisUtil.getSession()) { Map map = new LinkedHashMap<>(); BookMapper mapper = sqlSession.getMapper(BookMapper.class); mapper.getBookList().forEach(book -> map.put(book, set.contains(book.getBid()))); return map; } } BookServlet中修改doGetBookService service; @Override public void init() throws ServletException { service = new BookServiceImpl(); } context.setVariable("book_list", service.getBookList().keySet()); context.setVariable("book_list_status", new ArrayList<>(service.getBookList().values())); 修改books.index #JH2033 #JH2033 22/06/2021 $600 BookMapper中添加deleteBook方法@Delete("delete from book where bid = #{bid}") void deleteBook(int bid); BookService中添加deleteBook方法BookServiceImpl中实现deleteBook方法@Override public void deleteBook(int bid) { try (SqlSession sqlSession = MybatisUtil.getSession()) { BookMapper mapper = sqlSession.getMapper(BookMapper.class); mapper.deleteBook(bid); } } 修改books.html链接 添加书籍信息 servelt.manage.DeleteBookServlet@WebServlet("/delete-book") public class DeleteBookServlet extends HttpServlet { BookService service; @Override public void init() throws ServletException { service = new BookServiceImpl(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int bid = Integer.parseInt(req.getParameter("bid")); service.deleteBook(bid); resp.sendRedirect("books"); } } add-book.html同之前,借用add-borrow.html使用我们的模版form.html中的BookService中添加addBook方法BookMapper中添加addBook方法@Insert("insert into book(title, `desc`, price) values(#{title}, #{desc}, #{price})") void addBook(@Param("title") String title,@Param("desc") String desc,@Param("price") double price); BookServiceImpl中实现addBook方法@Override public void addBook(String title, String desc, double price) { try (SqlSession sqlSession = MybatisUtil.getSession()) { BookMapper mapper = sqlSession.getMapper(BookMapper.class); mapper.addBook(title, desc, price); } } servlet.manage.AddBookServlet@WebServlet("/add-book") public class AddBookServlet extends HttpServlet { BookService service; @Override public void init() throws ServletException { service = new BookServiceImpl(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ThymeleafUtil.process("add-book.html", new Context(), resp.getWriter()); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String title = req.getParameter("title"); String desc = req.getParameter("desc"); double price = Double.parseDouble(req.getParameter("price")); service.addBook(title, desc, price); resp.sendRedirect("books"); } } (七)完善项目以及打包发布StudentServlet中修改doGetBookService service; @Override public void init() throws ServletException { service = new BookServiceImpl(); } context.setVariable("student_list", service.getStudentList()); 修改students.html Scott Henry Scott Henry Scott Henry Scott Henry IndexServlet中修改doGet来获取学生书籍数量context.setVariable("book_count", service.getBookList().size()); context.setVariable("student_count", service.getStudentList().size()); 但其实这样写不好,失去了效率修改index.html显示数量LoginServlet中修改doPost和doGet实现“记住我”if (service.auth(username, password, req.getSession())) { if (remember != null) { Cookie cookie_username = new Cookie("username", username); cookie_username.setMaxAge(60 * 60 * 24 * 7); Cookie cookie_password = new Cookie("password", password); cookie_password.setMaxAge(60 * 60 * 24 * 7); resp.addCookie(cookie_username); resp.addCookie(cookie_password); } resp.sendRedirect("index"); Cookie[] cookies = req.getCookies(); if(cookies != null){ String username = null; String password = null; for (Cookie cookie : cookies) { if(cookie.getName().equals("username")) username = cookie.getValue(); if(cookie.getName().equals("password")) password = cookie.getValue(); } if(username != null && password != null){ if (service.auth(username, password, req.getSession())) { resp.sendRedirect("index"); return; } } } LogoutServlet@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getSession().removeAttribute("user"); Cookie cookie_username = new Cookie("username", "username"); cookie_username.setMaxAge(0); Cookie cookie_password = new Cookie("password", "password"); cookie_password.setMaxAge(0); resp.addCookie(cookie_username); resp.addCookie(cookie_password); resp.sendRedirect("login"); }
1 importjava.io.FileOutputStream;2 importjava.text.SimpleDateFormat;3 importjava.util.ArrayList;4 importjava.util.Date;5 importjava.util.List;67 importorg.apache.poi.hssf.usermodel.HSSFCell;8 importorg.apache.poi.hssf.usermodel.HSSFCellStyle;9 importorg.apache.poi.hssf.usermodel.HSSFRow;10 importorg.apache.poi.hssf.usermodel.HSSFSheet;11 importorg.apache.poi.hssf.usermodel.HSSFWorkbook;1213 /**14 * 程序入口15 *@authorDSH16 *17 */18 public classOutput {1920 @SuppressWarnings({ "deprecation", "unchecked", "rawtypes"})21 public static void main(String[] args) throwsException {2223 //创建一个webbook,对应一个Excel文件24 HSSFWorkbook wb = newHSSFWorkbook();25 //在webbook中添加一个sheet,对应Excel文件中的sheet26 HSSFSheet sheet = wb.createSheet("POI数据");27 //在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short28 HSSFRow row = sheet.createRow((int) 0);29 //创建单元格,并设置值表头 设置表头居中30 HSSFCellStyle style =wb.createCellStyle();31 style.setAlignment(HSSFCellStyle.ALIGN_CENTER); //创建一个居中格式3233 //设置表头34 HSSFCell cell = row.createCell((short) 0);35 cell.setCellValue("名称");36 cell.setCellStyle(style);37 cell = row.createCell((short) 1);38 cell.setCellValue("地址");39 cell.setCellStyle(style);40 cell = row.createCell((short) 2);41 cell.setCellValue("电话号码");42 cell.setCellStyle(style);43 cell = row.createCell((short) 3);44 cell.setCellValue("所属分类");45 cell.setCellStyle(style);46 cell = row.createCell((short) 4);47 cell.setCellValue("所在省份");48 cell.setCellStyle(style);49 cell = row.createCell((short) 5);50 cell.setCellValue("所在区县");51 cell.setCellStyle(style);52 cell = row.createCell((short) 6);53 cell.setCellValue("详细地址");54 cell.setCellStyle(style);55 cell = row.createCell((short) 7);56 cell.setCellValue("所属标签");57 cell.setCellStyle(style);58 cell = row.createCell((short) 8);59 cell.setCellValue("大地坐标——X");60 cell.setCellStyle(style);61 cell = row.createCell((short) 9);62 cell.setCellValue("大地坐标——Y");63 cell.setCellStyle(style);64 cell = row.createCell((short) 10);65 cell.setCellValue("火星坐标——X");66 cell.setCellStyle(style);67 cell = row.createCell((short) 11);68 cell.setCellValue("火星坐标——Y");69 cell.setCellStyle(style);70 cell = row.createCell((short) 12);71 cell.setCellValue("百度坐标——X");72 cell.setCellStyle(style);73 cell = row.createCell((short) 13);74 cell.setCellValue("百度坐标——Y");75 cell.setCellStyle(style);76 cell = row.createCell((short) 14);77 cell.setCellValue("条目");78 cell.setCellStyle(style);798081 List list = null;82 List listAll = new ArrayList();//保存全部数据83 for (int i = 1; i <= 2; i++) {//从第一页开始,,,,第二页截止(包含第二页)84 HtmlParseUtil htmlParseUtil = newHtmlParseUtil();85 //获取详细页86 list = htmlParseUtil.getContents("http://www.poi86.com/poi/district/1550/"+i+".html",i);87 listAll.addAll(list);//将所有数据放到一个list集合中88 }8990 for (int i = 0; i < listAll.size(); i++) {91 row = sheet.createRow((int) i + 1);9293 Content con =(Content) listAll.get(i);94 //创建单元格,并设置值95 row.createCell((short) 0).setCellValue(con.getName());96 row.createCell((short) 1).setCellValue(con.getAddress());97 row.createCell((short) 2).setCellValue(con.getPhone());98 row.createCell((short) 3).setCellValue(con.getType());99 row.createCell((short) 4).setCellValue(con.getProvince());100 row.createCell((short) 5).setCellValue(con.getArea());101 row.createCell((short) 6).setCellValue(con.getAddress_detail());102 row.createCell((short) 7).setCellValue(con.getLabel());103 row.createCell((short) 8).setCellValue(con.getDd_x());104 row.createCell((short) 9).setCellValue(con.getDd_y());105 row.createCell((short) 10).setCellValue(con.getHx_x());106 row.createCell((short) 11).setCellValue(con.getHx_y());107 row.createCell((short) 12).setCellValue(con.getBd_x());108 row.createCell((short) 13).setCellValue(con.getBd_y());109 row.createCell((short) 14).setCellValue(con.getRecord());110 }111 //将文件存到指定位置112 try{113 Date currentTime = newDate();114 SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");115 String date =formatter.format(currentTime);116117 FileOutputStream fout = new FileOutputStream("F:/content" + date + ".xls");118 wb.write(fout);119 fout.close();120 } catch(Exception e) {121 e.printStackTrace();122 }123 }124 }

我要回帖

更多关于 java怎么在控制台输出 的文章

 

随机推荐