JavaWeb
课程:【狂神说Java】JavaWeb入门到实战_哔哩哔哩_bilibili
一.基本概念
1.基本概念
- 静态web:html,css(提供给所有人看的数据,始终不会发生变化)
- 动态web:Servlet/JSP,ASP,PHP,淘宝等几乎所有的网站(提供给所有人看的数据,始终会发生变化,每个人在不同时间,不同地方看到的都不同)
2.web应用程序
web应用程序:可以提供浏览器访问的程序
- a.html、b.html等多个web资源,这些web资源可以被外界访问,对外界提供服务。
- 你们能访问到的任何一个页面或者资源,都存在于这个世界的某一个角落的计算机上。
- URL:统一资源定位符。
- 这个统一的web资源会被放在同一个文件夹下,web应用程序—>Tomcat:服务器。
- web应用程序编写完毕后,若想提供给外界访问:需要一个服务器来统一管理。
3.静态web
.htm,.html,这些都是网页的后缀,如果服务器上一直存在这些东西,我们就可以直接进行读取。
缺点:
(1)web页面无法更新,所有用户看到的都是同一个页面。(可以使用轮播图,实现伪动态)
(2)它无法和数据库交互(数据无法持久化,用户无法交互)
4.动态web
页面会动态展示:Web的页面展示的效果因人而异。
缺点:
(1)假如服务器的动态web资源出了问题,需要我们停机维护重新编写后台程序,重新发布。
优点:
弥补了静态web的缺点。
二.web服务器
1.技术讲解
2. web服务器
服务器是一种被动的操作,用来处理用户的一些请求和给用户一些响应信息。
(1)IIS:微软的服务器
(2)tomcat:
Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4和JSP2.0规范。
Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。、
对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat时,它实际上作为一个与Apache 独立的进程单独运行的。
三.tomcat详解
1.安装与启动
javaweb-03:Tomcat详解_哔哩哔哩_bilibili
2. 配置

请你谈谈网站是如何访问的?
- 输入一个域名,回车
-
检查本机的C:Windows\System32\drivers\etc\hosts配置文件下有没有这个域名映射
有:直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问。没有:去DNS服务器找,找到的话就返回,找不到就返回找不到。
3.解决中文乱码
查找以下文件:logging.properties,打开找到照片行显示的UTF-8,改成GBK
4.项目结构
四.Http
1.什么是http
HTTP(超文本传输协议)是一个简单的请求-响应协议,它通常运行在TCP之上。
- 文本:html,字符串…
- 超文本:图片,音乐,视频,定位,地图…
- 默认端口:80
HTTPS:安全的协议 - 默认端口:443
2.http的两个时代
- http1.0:客户端可以与web服务器连接后,只能获得一个web资源,断开连接。
- http2.0:客户端可以与web服务器连接后,可以获得多个web资源。
3.http请求 
客户端—->发请求(request)—->服务器(比如:访问百度)
(1)常规:
// 请求地址
Request URL: https://www.baidu.com/
// 请求方法
Request Method: GET
// 状态代码
Status Code: 200 OK
// 远程地址
Remote Address: 14.215.177.38:443
// 引用站点策略
Referrer Policy: strict-origin-when-cross-origin
(2)请求行:
- 请求行中的请求方式:GET
- 请求方式:Get,Post,HEAD,DELETE,PUT…
GET:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效。
POST:请求能够携带的参数没有限制,大小没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效。
(3)请求头(消息头)
Accept: text/html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Accept: 告诉浏览器,它所支持的数据类型
Accept-Encoding: 告诉浏览器,它支持哪种编码格式:GBK,UTF-8,GB2312,ISO8859-1
Accept-Language: 告诉浏览器,它的语言环境
Cache-Control: 缓存控制
Connection: 告诉浏览器,请求完成是断开还是保持
HOST:主机
4.http响应
// 缓存控制
Cache-Control: no-cache
// 保持连接(http1.1)
Connection: keep-alive
// 文本编码类型
Content-Encoding: gzip
// 响应类型
Content-Type: text/html;charset=utf-8
(1)响应体
Accept: 告诉浏览器,它所支持的数据类型
Accept-Encoding: 告诉浏览器,它支持哪种编码格式:GBK,UTF-8,GB2312,ISO8859-1
Accept-Language: 告诉浏览器,它的语言环境
Cache-Control: 缓存控制
Connection: 告诉浏览器,请求完成是断开还是保持
HOST:主机
Refrush:告诉客户端,多久刷新一次
Location:让网页重新定位
(2)响应状态码
- 200:响应成功
- 3xx:请求重定向(304等等)
- 4xx:找不到资源(404等等)
- 5xx:服务器代码错误(500代码错误,502网关错误)
五.Maven
帮我们自动导入配置jar包,Maven项目架构管理工具。
Maven 是一个项目管理工具,可以对 Java 项目进行构建、依赖管理。
Maven 也可被用于构建和管理各种项目,例如 C#,Ruby,Scala 和其他语言编写的项目。Maven 曾是 Jakarta 项目的子项目,现为由 Apache 软件基金会主持的独立 Apache 项目。
教程:javaweb-05:Maven环境搭建_哔哩哔哩_bilibili
Maven 能够帮助开发者完成以下工作:构建,文档生成,报告,依赖,SCMs,发布,分发,邮件列表
1.下载
IDEA 2018 2020 2021 2022 各版本对Maven版本兼容问题汇总:
IDEA 2018 2020 2021 2022 各版本对Maven版本兼容问题汇总_idea和maven版本对照-优快云博客
下载链接:
2. 配置与问题
Unable to import maven project: See logs for details问题的解决方法:
IDEA日常填坑:Cannot resolve plugin org.apache.maven.plugins:maven-war-plugin :
IDEA日常填坑:Cannot resolve plugin org.apache.maven.plugins:maven-war-plugin-优快云博客
IDEA中Maven Project 的Plugins项目出现红色波浪线解决办法:
Maven项目中出现红色波浪线的解决过程_maven plugins下有红色波浪线-优快云博客
3.web初始文件
常见问题:在IDEA中创建Maven项目时只有一个idea文件夹
在IDEA中创建Maven项目时没有src文件、不自动配置文件_2023idea创建maven项目没有src文件-优快云博客
普通maven项目
只有web情况下的maven项目
文件修改
补全mavenweb项目的文件
4.idea安装tomcat
错误:Error: Application Server not specified-优快云博客
5.在idea在运行项目与问题
问题:JavaWeb学习报错【HTTP Status 404 – 未找到】
JavaWeb学习报错【HTTP Status 404 – 未找到】_javawebhttp找不到状态-优快云博客
6.pom文件
idea创建项目没有target:idea创建项目没有target_idea 梅有target-优快云博客
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.xml</exclude>
</excludes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
六.Servlet
架包:
Maven Repository: javax.servlet.jsp » jsp-api (mvnrepository.com)
1.servlet简介
(1).Servlet就是sun公司开发动态web的一门技术。
(2).Sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:一.编写一个类,实现Servlet接口;二.把开发好的Java类部署到web服务器中。把实现了Servlet接口Java程序叫做,Servlet
Serlvet接口Sun公司有两个默认的实现类:HttpServlet,GenericServlet
2.HelloServlet
(1).构建一个普通的Maven项目,删掉里面的src目录,以后我们的学习就在这个项目里面建立Moudel;这个空的工程就是Maven主工程;
(2).关于Maven父子工程的理解:
父工程中会有:
<groupId>com.bash.web</groupId>
<artifactId>javaweb</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>web</module>
</modules>
子项目中会有:
<parent>
<groupId>com.bash.web</groupId>
<artifactId>javaweb</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
父项目中的jar包,子项目可以直接使用。反之,不可。
(3).Maven环境优化
- 修改web.xml为最新的
- 将maven的结构搭建完整
(4).编写一个Servlet程序
关于IDEA WEB项目的创建与无法继承HttpServlet问:
关于IDEA WEB项目的创建与无法继承HttpServlet问题_idea 继承不了 http-优快云博客
1.编写一个普通的类
2.实现Servlet接口,这里我们直接继承HttpServlet类
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("hello servlet");
PrintWriter writer = resp.getWriter();
writer.println("Hello Servlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
(5).编写Servlet的映射
为什么需要映射:我们写的是JAVA程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务中注册我们写的Servlet,还需给他一个浏览器能够访问的路径。
<!--注册servlet-->
<servlet>
<servlet-name>helloservlet</servlet-name>
<servlet-class>com.sunyiwenlong.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
<servlet-name>helloservlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
(6).配置tomcat
注意:配置项目发布路径就可以了
(7).启动测试
3. Servlet原理 
4. Mapping问题
- 一个Servlet可以指定一个映射路径
<servlet-mapping> <servlet-name>helloservlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
- 一个Servlet可以指定多个映射路径
<servlet-mapping> <servlet-name>helloservlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>helloservlet</servlet-name> <url-pattern>/hello2</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>helloservlet</servlet-name> <url-pattern>/hello3</url-pattern> </servlet-mapping>
- 一个Servlet可以指定通用映射路径
<servlet-mapping> <servlet-name>helloservlet</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
- 默认请求路径
<servlet-mapping> <servlet-name>helloservlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
- 指定一些后缀或者前缀等等…
<servlet-mapping> <servlet-name>helloservlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
- 优先级:固定优先,默认靠后
5.ServletContext
// string this.getInitParameter(); 获取初始化参数(web.xml文件中的初始化参数)
// ServletConfig this.getServletConfig(); 获取servlet的配置(web.xml文件中的配置)
// ServletContext this.getServletContext(); 获取servlet上下文
一.共享数据
public class SetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context =this.getServletContext();
String username = "fuck";
// void setAttribute(String s, Object o)将一个数据保存在了ServletContext中
context.setAttribute("username",username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context =this.getServletContext();
// object getAttribute(String s)从ServletContext中取出数据
String name = (String)context.getAttribute("username");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().println(name);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
// web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>helloservlet1</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloservlet1</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getservlet</servlet-name>
<servlet-class>GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getservlet</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
</web-app>
相当于容器,把值先存储进去,再取出来
二.获取初始化参数
// web.xml文件
<!--配置一些web应用一些初始化参数-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
public class ServletDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String url = this.getInitParameter("url");
resp.getWriter().println(url);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
三.请求转发
// web.xml文件
// 请求sd4
<servlet>
<servlet-name>gp</servlet-name>
<servlet-class>ServletDemo03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gp</servlet-name>
<url-pattern>/gp</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>sd4</servlet-name>
<servlet-class>ServletDemo04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sd4</servlet-name>
<url-pattern>/sd4</url-pattern>
</servlet-mapping>
// 请求/sd4找到ServletDemo04,ServletDemo04进行请求转发到/gp,到/gp的页面
// (浏览器路径是sd4的路径,页面拿到的是/gp的数据)
public class ServletDemo04 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
System.out.println("进入了demo04");
// RequestDispatcher requestDispatcher = context.getRequestDispatcher("String s");// 转发的路径
// requestDispatcher.forward(req,resp);// 调用forward请求转发
context.getRequestDispatcher("/gp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
第一个为请求转发,第二个为重定向
四.读取资源文件
public class ServletDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream stream = this.getServletContext().getResourceAsStream("/WEB-INF/CLASSES/db.properties");
Properties properties = new Properties();
properties.load(stream);
String username = properties.getProperty("username");
String password = properties.getProperty("password");
resp.getWriter().println(username+":"+password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
由于maven约定大于配置,所以要在pom.xml配置
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.xml</exclude>
</excludes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
6.HttpServletResponse
web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse;|
- 如果要获取客户端请求过来的参数:找HttpServletRequest
- 如果要给客户端响应一些信息:找HttpServletResponse
一.方法分类
负责向浏览器发送数据的方法
public ServletOutputStream getOutputStream() throws IOException;
public PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
响应的状态码
public static final int SC_CONTINUE = 100;
public static final int SC_OK = 200;
public static final int SC_MOVED_TEMPORARILY = 302;
public static final int SC_FOUND = 302;
public static final int SC_NOT_MODIFIED = 304;
public static final int SC_NOT_FOUND = 404;
public static final int SC_INTERNAL_SERVER_ERROR = 500;
public static final int SC_BAD_GATEWAY = 502;
二.应用
(1).向浏览器输出信息
前面使用的就是。
(2). 下载文件
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.要获取下载文件的路径
String realPath = "E:\\dev\\StudyProjects\\javaweb-servlet\\response\\src\\main\\resources\\大乔.jpg";
// 2.下载的文件名是啥?
String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);
// 3.设置想办法让浏览器能够支持下载我们需要的东西
resp.setHeader("Content-disposition","attachment;filename="+ URLEncoder.encode(filename,"utf-8"));
// 4.获取下载文件的输入流
FileInputStream in = new FileInputStream(realPath);
// 5.创建缓冲区
int len = 0;
byte[] buffer = new byte[1024];// 每次读取的长度
// 6.获取OutputStream对象
ServletOutputStream out = resp.getOutputStream();
// 7.将FileOutputStream流写入到bufer缓冲区
while ((len = in.read(buffer))>0){// 每次读取的长度大于0的情况下,就写出去
out.write(buffer,0,len);// 写出字节,从0写到len
}
// 8.使用OutputStream将缓冲区中的数据输出到客户端!
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
(3).验证码功能
public class ImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 让浏览器3秒刷新一次
resp.setHeader("refresh", "3");
// 在内存中创建一个图片
BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);// 宽、高、颜色
// 得到图片
Graphics2D g = (Graphics2D) image.getGraphics();// 得到一只2D的笔
// 设置图片的背景颜色
g.setColor(Color.white);
g.fillRect(0, 0, 80, 20);// 填充颜色
// 换个背景颜色
g.setColor(Color.BLUE);
// 设置字体样式:粗体,20
g.setFont(new Font(null,Font.BOLD,20));
// 画一个字符串(给图片写数据)
g.drawString(makeNum(),0,20);
// 告诉浏览器,这个请求用图片的方式打开
resp.setContentType("image/jpeg");
// 网站存在缓存,不让浏览器缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
// 把图片写给浏览器
boolean write = ImageIO.write(image, "jpg",resp.getOutputStream());
}
// 生成随机数
private String makeNum() {
Random random = new Random();
String num = random.nextInt(9999999) + "";// 随机数,最大七位,[0,9999999)
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 7 - num.length(); i++) {// 不足七位,则添加0
sb.append("0");
}
num = sb.toString()+num;// 不足七位,在随机数前面添加0
return num;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
(4).实现请求重定向
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*resp.setHeader("Location","/response_war/image");
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);*/
resp.sendRedirect("/response_war/image");// 重定向相当于上面两行代码
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
面试题:请你聊聊重定向和转发的区别?
相同点:页面都会实现跳转
不同点:
- 请求转发的时候,url地址栏不会产生变化。307
- 重定向时候,url地址栏会发生变化。302
7.HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息。
一.获取前端传递的参数
二.请求转发
前端:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobbys" value="代码"> 代码
<input type="checkbox" name="hobbys" value="唱歌"> 唱歌
<input type="checkbox" name="hobbys" value="女孩"> 女孩
<input type="checkbox" name="hobbys" value="电影"> 电影
<br>
<input type="submit" name="提交">
</form>
</body>
</html>
后端:
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 处理请求中文乱码(后期可以使用过滤器来解决)
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbys));
// 这里的 / 代表当前的web应用,所以不需要再加上/request_war这个上下文路径了,否则会出现404错误
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
}
web.xml
七.cookie/session
1.会话
无状态的会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话。
有状态的会话:一个用户打开一个浏览器,访问某些资源(网站),下次再来访问该资源(网站),我们会知道这个用户曾经来过,称之为有状态会话;
一个网站,怎么证明你来过?
- 服务端给客户端一个信件,客户端下次访问服务端带上信件就可以了;cookie(客户端)
- 服务器登记你来过了,下次你来的时候我来匹配你;seesion(服务端)
2.保存会话的两种技术
cookie:
- 客户端技术,(响应、请求)
session:
- 服务端技术,利用这个技术,可以保存用户的会话信息?我们可以把信息或者数据放在Session中。
3.Cookie 
(1).常用方法与使用
Cookie[] cookies = req.getCookies();// 获得cookie
cookie.getName();// 获得cookie中的key
cookie.getValue();// 获得cookie中的value
new Cookie("lastLoginTime",System.currentTimeMills()+"");// 新建一个cookie
cookie.setMaxAge(24*60*60);// 设置cookie的有效期,单位:秒
resp.addCookie(cookie);// 响应给客户端一个cookie
// 保存用户上一次访问的时间
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 服务器告诉你,你来的时间,把这个时间封装成一个信息,你下次带来,我就知道你上次来的时间
// 解决中文乱码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
PrintWriter out = resp.getWriter();
// Cookie,服务器端从客户端获取cookie
Cookie[] cookies = req.getCookies();// 数组,说明cookie可以有多个
// 判断cookie是否
if (cookies != null) {
out.write("你上一次登录的时间是:");
for (int i = 0; i < cookies.length; i++) {
// 获取cookie的名字
if (cookies[i].getName().equals("lastLoginTime")) {
// 获取cookie的值
long l = Long.parseLong(cookies[i].getValue());
Date date = new Date(l);
out.write(date.toLocaleString());
}
}
} else {
out.write("你是第一次登录!");
}
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
cookie.setMaxAge(24*60*60);// 设置cookie的有效期为一天,单位是:秒
resp.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
(2).删除cookie
- 不设置有效期,关闭浏览器,自动失效
- 设置有效期时间为0
(3).编码解码,解决中文乱码问题
URLEncoder.encode("张三","UTF-8")
URLDecoder.decode("张三","UTF-8")
(4).一个网站cookie是否存在上限!聊聊细节问题
cookie:一般会保存在本地的用户目录下appdata
- 一个Cookie只能保存一个信息;
- 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie;
- Cookie大小有限制4kb
- 300个cookie浏览器上限
4.session(重点) 
(1).什么是Session
- 服务器会给每一个用户(浏览器)创建一个Seesion对象。
- 一个session独占一个浏览器,只要浏览器没有关闭,这个session就存在。
- 用户登录之后,整个网站它都可以访问。(保存用户的信息;也可以保存购物车的信息)
(2).session的常用方法与使用
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决中文乱码
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=utf-8");
// 得到session
HttpSession session = req.getSession();
// 给session中存东西
session.setAttribute("name", "张三");
// 获取session的id
String sessionId = session.getId();
// 判断session是不是新创建
if (session.isNew()) {
resp.getWriter().write("session创建成功,ID:" + sessionId);
} else {
resp.getWriter().write("session已经存在了,ID:" + sessionId);
}
// session创建的时候做了什么事情
/*Cookie cookie = new Cookie("JSESSIONID", sessionId);
resp.addCookie(cookie);*/
//------------------
// 从session中获取数据
String name = (String) session.getAttribute("name");
//------------------
// 从session中删除指定name的数据
session.removeAttribute("name");
// 手动注销session
session.invalidate();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
(3).会话自动过期
<!--XML-->
<!--设置session默认的失效时间-->
<session-config>
<!--15分钟后session自动失效,以分钟为单位-->
<session-timeout>15</session-timeout>
</session-config>
(4).使用场景
- 保存一个登录用户的信息;
- 购物车信息;
- 在整个网站中经常会使用的数据,我们将它保存在Session中;
(5).session和cookie的区别
- Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
- Session把用户的数据写到用户独占Session中,服务器端保存(保存重要的信息,减少服务器资源的浪费)
- Session对象由服务创建;
八.jsp
1.什么是jsp
Java Server Pages:Java服务端页面,和servlet一样,用于动态web技术
最大的特点:
- 写jsp就像在写html
- 区别:
- html只给用户提供静态的数据
- jsp页面中可以嵌入Java代码,为用户提供动态数据
2.jsp原理
思路:jsp是怎样执行的?
- 代码层面没有任何问题
- 服务器内部工作
- tomcat中有一个work目录;IDEA中使用tomcat的会在IDEA的tomcat中生产一个work目录
- 目录地址C:\Users\26868\.IntelliJIdea2019.2\system\tomcat\Unnamed_web\work\
- 发现页面会被转换成为一个Java类!
- C:\Users\26868\.IntelliJIdea2019.2\system\tomcat\Unnamed_web\work\Catalina\localhost\webone\org\apache\jsp\src\main\web
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!
JSP最终也会被转换成为一个Java类!
JSP本质上就是一个Servlet
// 初始化
public void _jspInit() {
}
// 销毁
public void _jspDestroy() {
}
// JSPservice
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
- 判断请求的方式
-
内置一些对象(9个)
final javax.servlet.jsp.PageContext pageContext; // 页面上下文 javax.servlet.http.HttpSession session = null; // session final javax.servlet.ServletContext application; // applicationContext final javax.servlet.ServletConfig config; // config javax.servlet.jsp.JspWriter out = null; // out final java.lang.Object page = this; // page:当前 HttpServletRequest request; // 请求 HttpServletResponse response; // 响应
-
输出页面前增加的代码
response.setContentType("text/html;charset=UTF-8");// 设置响应的页面类型 pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out;
4.以上的内置对象可以在jsp页面中直接使用
5.原理图
在JSP页面中;
只要是JAVA代码就会原封不动的输出;
如果是HTML代码,就会被转换为:
out.write("<html>\r\n");
out.write("<head>\r\n");
这样的格式,输出到前端!
3.JSP基础语法
导入依赖
任何语言都有自己的语法,JAVA中有;
JSP作为java技术的一种应用,它拥有一些自己扩充的语法(了解,知道即可!),Java所有语法它都支持!
1.jsp表达式
<%--jsp表达式
作用:用来将程序的输出,输出到客户端
<%= 变量或表达式%>
--%>
<%= new java.util.Date() %>
2.jsp脚本片段
<%--jsp脚本片段--%>
<%
int sum = 0;
for (int i = 0; i < 100; i++) {
sum+=i;
}
out.print("<h1>sum="+sum+"</h1>");
%>
//--------------------------
<%--EL表达式:${变量} --%>
<%
for (int i = 0; i < 3; i++) {
%>
<h1>Hello World! ${i}</h1>
<%
}
%>
3.jsp声明
<%!
static {
System.out.println("loading Servlet!");
}
private int globalVar =0;
public void kuang(){
System.out.println("进入了该方法!");
}
%>
JSP声明:会被编译到jsp生成java的类中!
其他的,就会被生成到_jspService方法中!
在jsp,嵌入Java代码即可
4.jsp指令
<%@ page ... %>:声明页面属性,如内容类型、编码、缓冲等。
<%@ taglib prefix="..." uri="..." %>:导入外部标记库。
<%@ include file="..." %>:包含另一个 JSP 文件。
1.定制错误页面
<%--定制错误页面--%>
<%@ page errorPage="error/500.jsp" %>
或者在web.xml定制全局的错误页面
2.包含头部和尾部
5.九大内置对象
- PageContext
存东西
- Request
存东西
- Response
- Session
存东西
- Application(ServletContext)
存东西
- Config(ServletConfig)
- out
- page
- exception
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<% // 一.内置对象存储数据
// 保存的数据只在一个页面中有效
pageContext.setAttribute("one","1号");
// 保存的数据只在一次请求中有效,请求转发会携带这个数据
// 客户端向服务器发送请求,产生的数据,可能过会就用不上了,例:某个文章!
request.setAttribute("two","2号");
// 保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
// 客户端向服务器发送请求,产生的数据,可能用完了还要用,例:用户信息;
session.setAttribute("three","3号");
// 保存的数据只在服务器中有效,从打开服务器到关闭服务器
// 客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用。例:全局参数。
application.setAttribute("four","4号");
// 二.取数据,通过寻找的方式来取
String one = (String)pageContext.findAttribute("one");
String two = (String)pageContext.findAttribute("two");
String three = (String)pageContext.findAttribute("three");
String four = (String)pageContext.findAttribute("four");
String five = (String)pageContext.findAttribute("five");// 加入一个不存在的数据看看会怎么样
%>
<%= one %>
<%= two %>
<%= three %>
<%= four %>
<%= five %>
</body>
</html>
6.jsp标签、JSTL标签、EL表达式
<!-- JSTL表达式的依赖 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- standard标签库 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
1.JSP标签:JSP自带比较简单的标签。
<jsp:useBean ... %>:创建或查找 Bean 对象。
<jsp:setProperty ... %>:设置 Bean 对象的属性。
<jsp:getProperty ... %>:获取 Bean 对象的属性。
<jsp:forward ... %>:将请求转发到另一个 JSP 页面。
<jsp:include ... %>:将另一个 JSP 页面内容包含到当前页面。
<%-- 下面的表示转跳页面并设置信息http://localhost:8080/a.jsp?name=frank&age=19 --%>
<jsp:forward page="index.jsp">
<jsp:param name="name" value="frank"/>
<jsp:param name="age" value="19"/>
</jsp:forward>
<%-- 再index.jsp页面取参数 --%>
<%= request.getParameter("name")%>
<%= request.getParameter("age")%>
2.EL表达式: ${ }
- 获取数据
- 执行运算
- 获取web开发的常用对象
3.JSTL表达式
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签
教程: JSP 标准标签库(JSTL) | 菜鸟教程 (runoob.com)
- c:if
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<form action="index.jsp" method="get">
<%-- EL表达式获取表单中的数据 ${param.参数名} --%>
<input type="text" name="username" value="${param.username}">
<input type="submit" value="登录">
</form>
<%--判断如果提交的用户名是管理员,则登录成功,var为ture--%>
<c:if test="${param.username=='admin'}" var="isAdmin">
<c:out value="管理员欢迎您!"/>
</c:if>
<%--自闭合标签--%>
<c:out value="${isAdmin}"/>
</body>
</html>
c:set c:choose
c:when
<body>
<%--定义一个变量score,值为85--%>
<c:set var="score" value="55"/>
<c:choose>
<c:when test="${score>=90}">
你的成绩为优秀
</c:when>
<c:when test="${score>=80}">
你的成绩为一般
</c:when>
<c:when test="${score>=70}">
你的成绩为良好
</c:when>
<c:when test="${score<=60}">
你的成绩为不及格
</c:when>
</c:choose>
</body>
- c:forEach
<% List<String> nameLists = new ArrayList<>(); nameLists.add("张三"); nameLists.add("李四"); nameLists.add("王五"); nameLists.add("赵六"); nameLists.add("田六"); request.setAttribute("list",nameLists); %> <%-- var , 每一次遍历出来的变量 items, 要遍历的对象 begin, 哪里开始 end, 到哪里 step, 步长 --%> <c:forEach var="name" items="${list}"> <c:out value="${name}"/> <br> </c:forEach> <hr> <c:forEach var="name" items="${list}" begin="1" end="3" step="1" > <c:out value="${name}"/> <br> </c:forEach>
九.javaBean
1.JavaBean有特定的写法:
- 必须要有一个无参构造
- 属性必须私有化
- 必须有对应的get/set方法;
一般用来和数据库的字段做映射 ORM;
2.ORM :对象关系映射
- 表—->类
- 字段—>属性
- 行记录——>对象
3.user表
id | name | address | sex |
---|---|---|---|
1 | 张三 | 北京 | 男 |
2 | 李四 | 广东 | 男 |
3 | 王五 | 上海 | 男 |
class User{
private int id;
private String name;
private String address;
private String sex;
}
List<User> userList = new ArrayList<>();
userList.add(new User(1,"张三","北京","男"));
userList.add(new User(1,"李四","广东","男"));
userList.add(new User(1,"王五","上海","男"));
十.mvc三层架构
1.早些年没有mvc的时候 
用户直接访问控制层,控制层直接操作数据库
弊端:程序十分臃肿,不利于维护。(servlet代码中处理请求,响应,视图转跳,处理业务代码,处理逻辑代码,处理JDBC。
解决:架构(没有什么是加一层解决不了的)
2.什么是MVC
Model(模型),view(视图),Controller(控制器)
十一.过滤器(Filter)
1.用处
Filter:过滤器,用来过滤网站的数据:
- 处理中文乱码。
- 登录验证
2.Filter开发步骤:
(1).导包
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
</dependencies>
(2).编写过滤器(自定义类实现javax.servlet.Filter接口)
public class CharaterEncodingFilter implements Filter {
// 初始化:服务器启动的时候,就已经初始化了,随时等待过滤对象出现!
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharaterEncodingFilter初始化");
}
// chain:链
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
System.out.println("CharaterEncodingFilter执行前");
// 让我们的请求继续走,如果不写,程序到这里就被拦截停止
chain.doFilter(request,response);
System.out.println("CharaterEncodingFilter执行后");
}
// 销毁:web服务器关闭的时候,过滤会被销毁
@Override
public void destroy() {
System.out.println("CharaterEncodingFilter销毁");
}
}
(3).在web.xml中配置Filter
<filter>
<filter-name>filter</filter-name>
<filter-class>com.sunyiwenlong.filter.CharaterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<!--只要是/servlet的任何请求,会经过这个过滤器-->
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
3.应用:模拟用户登入
jsp
<body>
<h1>登入页面</h1>
<%--action: 提交的到处理登入的UserName类的映射路径下--%>
<form action="/username" method="post">
用户名:<input type="text" name="username">
提交:<input type="submit">
</form>
</body>
<body>
<h1>主页</h1>
<%--提交 提交到处理注销的Delete类映射路径下 --%>
<a href="/delete"><samp>注销</samp></a>
</body>
<body>
<h1>用户错误</h1>
<a href="index.jsp"><span>转跳到登入页面</span></a>
</body>
java
// 处理用户登入
public class UserName extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 取出用户名
String name = req.getParameter("username");
// 判断用户名
if (name.equals("123")) {// 用户名正确
// 生成用户id
req.getSession().setAttribute(Const.USER_SESSION,req.getSession().getId());
// 转跳成功页面
resp.sendRedirect("/sys/yes.jsp");
} else { // 用户名错误
// 转跳错误页面
resp.sendRedirect("/no.jsp");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
// 实现注销
public class Delete extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 取出用户id
String id = (String) req.getSession().getAttribute(Const.USER_SESSION);
// 判断是否有id
if (id != null) {
// 注销
req.getSession().removeAttribute(Const.USER_SESSION);
// 转跳登入页面
resp.sendRedirect("/index.jsp");
} else {
// id为空,直接返回登入页面
resp.sendRedirect("/index.jsp");
// 有一个问题,已经为null为什么还能加入欢迎页面,点击注销。
// 如何解决,我们可以使用过滤器,处理为null的情况
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
// 处理注销时为null的问题
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 如何拿到id,先向下转型,再拿id
HttpServletRequest req = (HttpServletRequest)servletRequest;
HttpServletResponse resp = (HttpServletResponse)servletResponse;
String id = (String) req.getSession().getAttribute(Const.USER_SESSION);
// 如果id为null,直接转跳到错误页面
if (id == null) {
resp.sendRedirect("/no.jsp");
}
filterChain.doFilter(req,resp);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void destroy() { }
}
XML
<filter>
<filter-name>myfilter</filter-name>
<filter-class>MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myfilter</filter-name>
<url-pattern>/sys/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>username</servlet-name>
<servlet-class>UserName</servlet-class>
</servlet>
<servlet>
<servlet-name>delete</servlet-name>
<servlet-class>Delete</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>username</servlet-name>
<url-pattern>/username</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>delete</servlet-name>
<url-pattern>/delete</url-pattern>
</servlet-mapping>
注意要给主页页面单独开一个文件夹,不然会报错 localhost 重定向次数过多
localhost 将您重定向的次数过多问题解决。_重定向次数过多清除也没用-优快云博客
十二.监听器
实现一个监听器的接口;(有N种监听器)
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
// 统计在线人数
public class ListenerTest implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
ServletContext context = se.getSession().getServletContext();
Integer onlineCount = (Integer) context.getAttribute("OnlineCount");
if (onlineCount==null){
onlineCount = new Integer(1);
}else {
int count = onlineCount.intValue();
onlineCount = new Integer(count+1);
}
context.setAttribute("OnlineCount",onlineCount);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext context = se.getSession().getServletContext();
Integer onlineCount = (Integer) context.getAttribute("OnlineCount");
if (onlineCount==null){
onlineCount = new Integer(0);
}else {
int count = onlineCount.intValue();
onlineCount = new Integer(count-1);
}
context.setAttribute("OnlineCount",onlineCount);
}
}
jsp
<h1>当前<span><%= getServletConfig().getServletContext().getAttribute("OnlineCount")%></span>人在线</h1>
XML
<listener>
<listener-class>com.sunyiwenlong.listener.OnlineCountListener</listener-class>
</listener>
十三.JDBC复习
1.基础复习
基础知识:Java进阶十—JDBC-优快云博客
2.Idea连接数据库
Intellij IDEA——配置MySQL的驱动程序_idea配置mysql驱动-优快云博客
超详细的Idea与MySQL的连接(从入门到精通)_idea连接数据库-优快云博客
3.事务
import java.sql.*;
public class UDBCTest {
// 配置
public static final String URL = "jdbc:mysql://localhost:3306/student";
public static final String USER = "root";
public static final String PASSWORD = "123456";
public static final String DRIVER = "com.mysql.cj.jdbc.Driver";
public static Connection connection;
public static void main(String[] args) {
try {
// 1.加载驱动
Class.forName(DRIVER);
// 2.连接数据库
connection = DriverManager.getConnection(URL,USER,PASSWORD);
// 3.通知数据库开启事务,false开启
connection.setAutoCommit(false);
// 4.执行sql语句
String sqlOne = " update student set age=33-10 where id=1";
connection.prepareStatement(sqlOne).executeUpdate();
String sqlTwo = "update student set age=56+10 where id=2";
connection.prepareStatement(sqlTwo).executeUpdate();
// 4.提交事务
connection.commit();
} catch (ClassNotFoundException e) {
// 5.如果遇到异常,那就回滚事务
try {
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
// 6.关闭
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
十四.文件传输原理及实现
1.基础配置
- 修改web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0" metadata-complete="true"> </web-app>
- 配置Tomcat,运行空项目。
- 导入架包:文件在网络上都是使用IO的方式,即流的方式进行的传输,要实现的文件上传功能可以直接使用apache的组件commons-fileupload(针对文件上传的工具类包),这个jar包又依赖commons-io包(封装了大量的IO操作的工具类),所以在实现文件上传功能的时候需要导入如下两个依赖:
<!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5</version> </dependency> <!--servlet依赖--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency>
2.整体框架
3.编写前端与支持
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<%--
通过表单上传文件
get:上传文件有大小限制
post:上传文件无大小限制
enctype="multipart/form-data"支持上传文件格式
--%>
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
<p>上传用户<input type="text" name="username"></p>
<p>上传文件1<input type="file" name="file1"></p>
<p>上传文件2<input type="file" name="file2"></p>
<p><input type="submit"> | <input type="reset"></p>
</form>
</body>
</html>
<%--
Created by IntelliJ IDEA.
User: 26868
Date: 2024/3/16
Time: 16:24
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
4.后端编写
先配置web.xml
<servlet>
<servlet-name>upload</servlet-name>
<servlet-class>com.github.servlet.FileSerlvet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>upload</servlet-name>
<url-pattern>/upload.do</url-pattern>
</servlet-mapping>
编写FileSerlvet类
// ServletFileUpload类
// 一.构造器
// ServletFileUpload() 创建一个 ServletFileUpload 实例,使用默认设置。
// ServletFileUpload(factory) 创建一个上传工具,指定使用缓存区与临时文件存储位置.
// 二.常用方法
// 1.static final boolean isMultipartContent(HttpServletRequest request) 检查请求是否 是multipart/form-data类型的请求。
// 2.void setProgressListener(ProgressListener pListener) 监听进度
// 会重新ProgressListener接口,update方法的三个参数为已读字节数,总内容长度(以字节为单位),已处理的项目数。
// 3.void setHeaderEncoding(String encoding) 设置字符编码
// 4.void setFileSizeMax(long fileSizeMax) 设置文件读取大小、
// 5.List<FileItem> parseRequest(HttpServletRequest request) 解析请求并提取文件项
// DiskFileItemFactory类
// 一.构造器
// DiskFileItemFactory() - 创建一个新的 DiskFileItemFactory 实例,使用默认设置。
// 二.常用方法
// 1.void setSizeThreshold(int sizeThreshold) 设置缓冲区大小
// 2.void setRepository(File repository) 设置用于存储临时文件的目录
// UUID类通用唯一识别码
// 一.构造器(不常用)
// 二.常用方法
// 1.static UUID randomUUID() 生成一个新的随机UUID
// 2.tring toString() 将UUID转换为字符串表示
// FileItem类
// 一.构造器(不常用)
// 二.常用方法
// 1..boolean isFormField() 判断上传的文件是普通的表单还是带文件的表单
// 2.InputStream getInputStream() 获取输入流
// 2.String getFieldName() 获取前端普通表单name参数
// 3.String getString(String var1) 获取前端普通表单的值,var1设置编码格式
// 4.void getName(): 返回文件的文件名。
// 5.void getSize(): 返回文件的大小。
// 6.void delete(): 删除文件。
// 一些技巧
// 获得上传的文件名/images/girl/paojie.png
//String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
// 获得文件的后缀名
//String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
// getServletContext方法
// 1.String getRealPath(String var1) 将给定的虚拟路径转换为服务器文件系统中的绝对路径
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
/**
* @author subei
*/
public class FileSerlvet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.判断上传的文件普通表单还是带文件的表单
if (!ServletFileUpload.isMultipartContent(request)) {
return;//终止方法运行,说明这是一个普通的表单,直接返回
}
// 2.创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访间上传的文件;
String uploadPath =this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(uploadPath);
if (!uploadFile.exists()){
uploadFile.mkdir(); //创建这个月录
}
// 3.创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件
String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File file = new File(tmpPath);
if (!file.exists()) {
file.mkdir();//创建临时目录
}
// 处理上传的文件,一般都需要通过流来获取,我们可以使用 request, getInputstream(),原生态的文件上传流获取,十分麻烦
// 但是我们都建议使用 Apache的文件上传组件来实现, common-fileupload,它需要旅 commons-io组件;
// 这里我们把它们提炼成一个一个方法,然后调用
try {
// 4.调用下面写好的getDiskFileItemFactory方法,来判断文件的大小与限制
DiskFileItemFactory factory = getDiskFileItemFactory(file);
// 5.调用下面写好的getServletFileUpload方法,监听文件读取进度与文件上传的总大小
ServletFileUpload upload = getServletFileUpload(factory);
// 6.调用下面写好的uploadParseRequest方法,处理上传文件
// 把前端请求解析,封装成FileItem对象,需要从ServletFileUpload对象中获取
String msg = uploadParseRequest(upload, request, uploadPath);
// Servlet请求转发消息
System.out.println(msg);
if(msg == "文件上传成功!") {
// Servlet请求转发消息
request.setAttribute("msg",msg);
request.getRequestDispatcher("success.jsp").forward(request, response);
}else {
msg ="请上传文件";
request.setAttribute("msg",msg);
request.getRequestDispatcher("success.jsp").forward(request, response);
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
// 4.判断文件的大小与限制
public static DiskFileItemFactory getDiskFileItemFactory(File file) {
DiskFileItemFactory factory = new DiskFileItemFactory();
// 通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将他放到临时文件中;
factory.setSizeThreshold(1024 * 1024);// 缓冲区大小为1M
factory.setRepository(file);// 临时目录的保存目录,需要一个file
return factory;
}
// 5.监听文件读取进度与文件上传的总大小
public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
// 创建一个上传工具,指定使用缓存区与临时文件存储位置
ServletFileUpload upload = new ServletFileUpload(factory);
// 监听长传进度
upload.setProgressListener(new ProgressListener() {
// 三个参数为已读字节数,总内容长度(以字节为单位),已处理的项目数
public void update(long l, long l1, int i) {
System.out.println("以读取"+((l/l1)*100)+"%");
}
});
// 处理乱码问题
upload.setHeaderEncoding("UTF-8");
// 设置单个文件的最大值
upload.setFileSizeMax(1024 * 1024 * 10);
// 设置总共能够上传文件的大小
// 1024 = 1kb * 1024 = 1M * 10 = 10м
return upload;
}
// 6.处理上传文件
public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath) throws FileUploadException, IOException {
String msg = "";
// 把前端请求解析,封装成FileItem对象
List<FileItem> fileItems = upload.parseRequest(request);
for (FileItem fileItem : fileItems) {
if (fileItem.isFormField()) {// 判断上传的文件是普通的表单还是带文件的表单
// getFieldName指的是前端表单控件的name;
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8"); // 处理乱码
System.out.println(name + ": " + value);
} else {// 判断它是上传的文件
// ============处理文件==============
// 拿到文件名
String uploadFileName = fileItem.getName();
System.out.println("上传的文件名: " + uploadFileName);
if (uploadFileName.trim().equals("") || uploadFileName == null) {
continue;
}
// 获得上传的文件名/images/girl/paojie.png
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
// 获得文件的后缀名
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
/*
* 如果文件后缀名fileExtName不是我们所需要的 就直按return.不处理,告诉用户文件类型不对。
*/
System.out.println("文件信息[件名: " + fileName + " ---文件类型" + fileExtName + "]");
// 可以使用UID(唯一识别的通用码),保证文件名唯
// 0UID. randomUUID(),随机生一个唯一识别的通用码;
String uuidPath = UUID.randomUUID().toString();
// ================处理文件完毕==============
// 存到哪? uploadPath
// 文件真实存在的路径realPath
String realPath = uploadPath + "/" + uuidPath;
// 给每个文件创建一个对应的文件夹
File realPathFile = new File(realPath);
if (!realPathFile.exists()) {
realPathFile.mkdir();
}
// ==============存放地址完毕==============
// 获得文件上传的流
InputStream inputStream = fileItem.getInputStream();
// 创建一个文件输出流
// realPath =真实的文件夹;
// 差了一个文件;加上翰出文件的名产"/"+uuidFileName
FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);
// 创建一个缓冲区
byte[] buffer = new byte[1024 * 1024];
// 判断是否读取完毕
int len = 0;
// 如果大于0说明还存在数据;
while ((len = inputStream.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
// 关闭流
fos.close();
inputStream.close();
msg = "文件上传成功!";
fileItem.delete(); // 上传成功,清除临时文件
//=============文件传输完成=============
}
}
return msg;
}
}
十五.邮件发送原理及实现
1.原理 
- SMTP协议
发送邮件:
我们通常把处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器)。 - POP3协议
接收邮件:
我们通常把处理用户pop3请求(邮件接收请求)的服务器称之为POP3服务器(邮件接收服务器)
2.引入架包
Maven Repository: javax.mail » mail » 1.4.7 (mvnrepository.com)
Maven Repository: javax.activation » activation » 1.1.1 (mvnrepository.com)
3.简单邮件:纯文本
需要发送邮件首先就要我们的邮箱账号支持POP3和SMTP协议,所以我们需要开启邮箱的POP3+SMTP服务,然后我们需要复制下图中的授权码,这个授权码就相当于你的QQ密码,你可以使用你的邮箱账号+授权码来发送邮件,而SMTP服务器也就是使用这个来识别你的身份的
package com.github.test;
import com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
/**
* @Author: subei
* @Description: 一封简单的邮件
*/
public class MailDemo01 {
public static void main(String[] args) throws Exception {
Properties prop = new Properties();
prop.setProperty("mail.host", "smtp.qq.com");
// 设置QQ邮件服务器
prop.setProperty("mail.transport.protocol", "smtp");
// 邮件发送协议
prop.setProperty("mail.smtp.auth", "true");
// 需要验证用户名密码
// 关于QQ邮箱,还要设置SSL加密,加上以下代码即可
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);
// 使用JavaMail发送邮件的5个步骤
// 1.创建定义整个应用程序所需的环境信息的 Session 对象
// 使用QQ邮箱的时候才需要,其他邮箱不需要这一段代码
Session session = Session.getDefaultInstance(prop, new Authenticator() {
// 获取和SMTP服务器的连接对象
@Override
public PasswordAuthentication getPasswordAuthentication() {
// 发件人邮件用户名、授权码
return new PasswordAuthentication("XXXX@qq.com", "授权码");
}
});
// 开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
session.setDebug(true);
// 2.通过session得到transport对象
Transport ts = session.getTransport();
// 通过这一次和SMTP服务器的连接对象获取发送邮件的传输对象
// 3.使用邮箱的用户名和授权码连上SMTP邮件服务器,即登陆
ts.connect("smtp.qq.com", "XXXX@qq.com", "授权码");
// 4.创建邮件对象MimeMessage——点击网页上的写信
// 创建一个邮件对象
MimeMessage message = new MimeMessage(session);
// 指明邮件的发件人——在网页上填写发件人
message.setFrom(new InternetAddress("XXXX@qq.com"));
// 设置发件人
// 指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发——在网页上填写收件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress("XXXX@qq.com"));
// 设置收件人
// 邮件的标题——在网页上填写邮件标题
message.setSubject("简单邮件发送实现");
// 设置邮件主题
// 邮件的文本内容——在网页上填写邮件内容
message.setContent("<h2 style='color:red'>你好啊!</h2>", "text/html;charset=UTF-8");
// 设置邮件的具体内容
// 5.发送邮件——在网页上点击发送按钮
ts.sendMessage(message, message.getAllRecipients());
// 6.关闭连接对象,即关闭服务器上的连接资源
ts.close();
}
}
4.复杂邮件:有附件(图片,视频等等)
import com.sun.mail.util.MailSSLSocketFactory;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.util.Properties;
/**
* @Author: subei
* @Description: 图片的邮件
*/
public class MailDemo01 {
public static void main(String[] args) throws Exception {
Properties prop = new Properties();
prop.setProperty("mail.host", "smtp.qq.com");
// 设置QQ邮件服务器
prop.setProperty("mail.transport.protocol", "smtp");
// 邮件发送协议
prop.setProperty("mail.smtp.auth", "true");
// 需要验证用户名密码
// 关于QQ邮箱,还要设置SSL加密,加上以下代码即可
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
prop.put("mail.smtp.ssl.enable", "true");
prop.put("mail.smtp.ssl.socketFactory", sf);
// 使用JavaMail发送邮件的5个步骤
// 1.创建定义整个应用程序所需的环境信息的 Session 对象
// 使用QQ邮箱的时候才需要,其他邮箱不需要这一段代码
Session session = Session.getDefaultInstance(prop, new Authenticator() {
// 获取和SMTP服务器的连接对象
@Override
public PasswordAuthentication getPasswordAuthentication() {
// 发件人邮件用户名、授权码
return new PasswordAuthentication("XXXX@qq.com", "授权码");
}
});
// 开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
session.setDebug(true);
// 2.通过session得到transport对象
Transport ts = session.getTransport();
// 通过这一次和SMTP服务器的连接对象获取发送邮件的传输对象
// 3.使用邮箱的用户名和授权码连上SMTP邮件服务器,即登陆
ts.connect("smtp.qq.com", "XXXX@qq.com", "授权码");
// 4.创建邮件对象MimeMessage——点击网页上的写信
// 创建一个邮件对象
MimeMessage message = new MimeMessage(session);
// 指明邮件的发件人——在网页上填写发件人
message.setFrom(new InternetAddress("XXXX@qq.com"));
// 设置发件人
// 指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发——在网页上填写收件人
message.setRecipient(Message.RecipientType.TO, new InternetAddress("XXXX@qq.com"));
// 设置收件人
// 邮件的标题——在网页上填写邮件标题
message.setSubject("简单邮件发送实现");
// 设置邮件主题
System.out.println("=============================复杂邮件的邮件内容设置==================================");
// 准备邮件数据
// 准备图片数据
// 获取一个图片的MimeBodyPart对象
MimeBodyPart image = new MimeBodyPart();
// 由于图片需要字符化才能传输,所以需要获取一个DataHandler对象
DataHandler dh = new DataHandler(new FileDataSource("图片的绝对地址"));
// 将图片序列化
image.setDataHandler(dh);
// 为图片的MimeBodyPart对象设置一个ID,我们在文字中就可以使用它了
image.setContentID("p6.jpg");
// 准备正文数据
MimeBodyPart text = new MimeBodyPart();
// 获取一个文本的MimeBodyPart对象
text.setContent("这是一封邮件正文带图片<img src='cid:p6.jpg'>的邮件", "text/html;charset=UTF-8");
// 设置文本内容,注意在里面嵌入了<img src='cid:p6.jpg'>
// 描述数据关系
// 获取MimeMultipart
MimeMultipart mm = new MimeMultipart();
// 将文本MimeBodyPart对象加入MimeMultipart中
mm.addBodyPart(text);
// 将图片MimeBodyPart对象加入MimeMultipart中
mm.addBodyPart(image);
// 设置MimeMultipart对象的相对熟悉为related,即发送的数据为文本+非附件资源
mm.setSubType("related");
// 设置到消息中,保存修改
message.setContent(mm);
// 将MimeMultipart放入消息对象中
message.saveChanges();
// 保存上面的修改
System.out.println("===============================================================");
// 5.发送邮件——在网页上点击发送按钮
ts.sendMessage(message, message.getAllRecipients());
// 6.关闭连接对象,即关闭服务器上的连接资源
ts.close();
}
}
发送包含附件的复杂邮件
System.out.println("=============================复杂邮件的邮件内容设置==================================");
// 图片
MimeBodyPart body1 = new MimeBodyPart();
body1.setDataHandler(new DataHandler(new FileDataSource("图片的绝对地址")));
// 图片设置ID
body1.setContentID("some.png");
// 文本
MimeBodyPart body2 = new MimeBodyPart();
body2.setContent("请注意,这是文本附件<img src='cid:test.png'>","text/html;charset=utf-8");
// 附件
MimeBodyPart body3 = new MimeBodyPart();
body3.setDataHandler(new DataHandler(new FileDataSource("附件1的绝对地址")));
// 附件设置名字
body3.setFileName("demo.c");
MimeBodyPart body4 = new MimeBodyPart();
body4.setDataHandler(new DataHandler(new FileDataSource("附件2的绝对地址")));
// 附件设置名字
body4.setFileName("demo.txt");
// 拼装邮件正文内容
MimeMultipart multipart1 = new MimeMultipart();
multipart1.addBodyPart(body1);
multipart1.addBodyPart(body2);
// 1.文本和图片内嵌成功!
multipart1.setSubType("related");
// new MimeBodyPart().setContent(multipart1);
// 将拼装好的正文内容设置为主体
MimeBodyPart contentText = new MimeBodyPart();
contentText.setContent(multipart1);
// 拼接附件
MimeMultipart allFile =new MimeMultipart();
// 附件
allFile.addBodyPart(body3);
// 附件
allFile.addBodyPart(body4);
// 正文
allFile.addBodyPart(contentText);
// 正文和附件都存在邮件中,所有类型设置为mixed;
allFile.setSubType("mixed");
// 设置到消息中,保存修改
message.setContent(allFile);
// 将MimeMultipart放入消息对象中
message.saveChanges();
// 保存上面的修改
System.out.println("===============================================================");
5.网站注册发送邮件功能实现
(1).前端编写
<%@ page contentType="text/html;charset=UTF-8" %>
<%--注册填写邮箱的前端页面--%>
<html>
<head>
<title>注册</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/RegisterServlet.do" method="post">
用户名:<input type="text" name="username"><br/>
密码:<input type="password" name="password"><br/>
邮箱:<input type="text" name="email"><br/>
<input type="submit" value="注册">
</form>
</body>
</html>
(2).后端编写
- 编写实体类编写User.java,下面是封装架包
Maven Repository: org.projectlombok » lombok » 1.18.24 (mvnrepository.com)
package com.pojo;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String username;
private String password;
private String email;
}
- 编写工具类Sendmail.java
package com.util; /** * 多线程实现邮件发送 * 使用多线程的原因就是提高用户的体验,一旦一个页面3s及以上的时间白屏就可能被用户关掉 * 所以我们在用户提交表单之后,将费时的邮件发送工作使用一个子线程来完成,而主线程还是去完成它自己的事情 * 这么做就可以提高用户体验,不然用户等待邮件发送的时间 */ import com.github.pojo.User; import com.sun.mail.util.MailSSLSocketFactory; import javax.mail.*; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.util.Properties; /** * @author subei * 多线程这种处理就可以称为异步处理 */ public class Sendmail extends Thread{ // 用于向客户发送邮件的邮箱 private String from = "XXXX@qq.com"; // 用于登陆SMTP服务器的用户名 private String username = "XXXX@qq.com"; // 授权码 private String password = "授权码"; // 发送邮件的地址 private String host = "smtp.qq.com"; private User user; public Sendmail(User user) { this.user = user; } @Override public void run() { try { Properties prop = new Properties(); // 设置QQ邮件服务器 prop.setProperty("mail.host", host); // 邮件发送协议 prop.setProperty("mail.transport.protocol", "smtp"); // 需要验证用户名密码 prop.setProperty("mail.smtp.auth", "true"); // 关于QQ邮箱,还要设置SSL加密,加上以下代码即可 MailSSLSocketFactory sf = new MailSSLSocketFactory(); sf.setTrustAllHosts(true); prop.put("mail.smtp.ssl.enable", "true"); prop.put("mail.smtp.ssl.socketFactory", sf); // 1.创建定义整个应用程序所需的环境信息的 Session 对象 // 使用QQ邮箱的时候才需要,其他邮箱不需要这一段代码 // 获取和SMTP服务器的连接对象 Session session = Session.getDefaultInstance(prop, new Authenticator() { @Override public PasswordAuthentication getPasswordAuthentication() { // 发件人邮件用户名、授权码 return new PasswordAuthentication("XXXX@qq.com", "授权码"); } }); // 开启Session的debug模式,这样就可以查看到程序发送Email的运行状态 session.setDebug(true); // 2.通过session得到transport对象 Transport ts = session.getTransport(); // 3.使用邮箱的用户名和授权码连上SMTP邮件服务器,即登陆 ts.connect(host, username, password); //4、创建邮件对象MimeMessage——点击网页上的写信 MimeMessage message = new MimeMessage(session); message.setFrom(new InternetAddress(username)); message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail())); message.setSubject("用户注册邮件!"); message.setContent("<p><h2>恭喜注册成功!</h2></p>您的用户名为: <h4>"+user.getUsername()+ "</h4><p>您的密码:" + user.getPassword() + "</p><p>请妥善保管您的密码,如有问题请及时联系网站客服,再次欢迎您的加入!!</p>", "text/html;charset=UTF-8"); // 5.发送邮件——在网页上点击发送按钮 ts.sendMessage(message, message.getAllRecipients()); // 6.关闭连接对象,即关闭服务器上的连接资源 ts.close(); } catch (Exception e) { e.printStackTrace(); } } }
- 编写Servlet.java
package com.servlet; import com.github.pojo.User; import com.github.util.Sendmail; 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 RegisterServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1.接收用户填写的表单数据 String username = req.getParameter("username"); String password = req.getParameter("password"); String email = req.getParameter("email"); System.out.println(username+password+email); // 2.向用户邮箱发送邮件,注意发送邮件很耗时,所以我们启动一个子线程去做这件事,而用户则是直接跳转注册成功页面,以免降低用户体验 User user = new User(username,password,email); // 获取子线程对象 Sendmail sendmail = new Sendmail(user); // 启动子线程 new Thread(sendmail).start(); // 3.视图跳转 req.setAttribute("message","注册成功!我们已经向您的邮箱发送了邮件,请您及时进行查收。由于网络原因,您收到邮件的时间存在延迟,敬请谅解~"); req.getRequestDispatcher("info.jsp").forward(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
- web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>RegisterServlet</servlet-name> <servlet-class>com.github.servlet.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>RegisterServlet</servlet-name> <url-pattern>/RegisterServlet.do</url-pattern> </servlet-mapping> </web-app>
- 运行测试,遇到如下报错。
-
- 检查Artifacts;
-
- 再次运行,还是报错500;
- 将activation-1.1.jar、mail-1.4.7.jar导入到Tomcat中的lib文件夹中。
-
- 再次运行。
-