JavaWeb
【完成周期23-5-5-------23-5-22】
Web服务器
1. 技术讲解
1.1ASP
- 属于微软的,在html中嵌入VB脚本,常用c#,代码过于混乱
1.2PHP
- 开发速度快,功能强大,跨平台,代码简单
- 无法承载访问量大的情况(局限)
1.3JSP/Servlet
- 使用B/S架构,浏览器服务器,可以承担三高问题(高可靠,高并发,高性能)
2.WEB服务器
概念:处理用户请求并给用户相应的响应
静态web:资源 不变,无法与数据库交互
动态web:显示资源因人而异,可以与数据库交互
2.1Tomcat
-
安装包下的文件夹含义
tomcat系统各个文件夹目录是什么意义: bin:放置的是Tomcat一些相关的命令,启动的命令(startup)和关闭的命令(shutdown)等等 conf:(configure)配置文件 lib:(library)库,依赖的 jar包 logs:Tomcat 的日志文件 temp:Tomcat的临时文件夹 webapps:可执行的项目。默认作为存放开发项目的目录 work:存放由 jsp翻译成的 .java源文件以及编译的 .class字节码文件(jsp -->java -->class)
-
Tomcat 配置环境变量:点击startup.bat启动tomcat服务器【需要配置环境变量】
·
- IIS
3. HTTP
3.1 什么是超文本
使用超链接将不同空间位置的文本信息链接到一起
3.2 两个版本
- 1.0 浏览器请求服务器单个资源,服务器返回资源完 便断开连接
- 2.0 浏览器可请求服务器多个资源,服务器返回资源后 不会断开连接,需主动断开,或者双方都空余一段时间后自己断开连接
3.3HTTP请求
-
请求行
-
POST /examples/servlets/servlet/RequestParamExample HTTP/1.1
- Get :高效,有大小限制,会在地址栏显示,不安全
- POST:不高效,没有大小限制,不会在地址栏显示,安全
-
请求头
Accept:客户端向服务器端表示,我能支持什么类型的数据。
Referer:真正请求的地址路径,全路径
Accept-Language:支持语言格式
User-Agent:用户代理向服务器表明,当前来访的客户端信息。
Content-Type:提交的数据类型。经过urlencoding编码的form表单的数据
Accept-Encoding:压缩算法 。
Connection:保持连接
Cache-Control:对缓存的操作 -
请求体
- name=“abc”&password=“123”
3.4HTTP响应
-
响应行
-
响应状态码
- 2xx 成功
- 3xx 重定向
- 4xx网页不存在
- 5xx 服务器错误 502网关错误
-
HTTP/1.1 200 OK
-
-
响应头
Server:服务器是哪一种类型。Tomcat
Content-Type:服务器返回给客户端的内容类型
Content-Length:返回的数据长度
Date:通讯的日期,响 应的时间 -
响应体
- 就是接口返回的数据的类型,一般是json串
4.Maven
4.1 Maven是什么?
Maven是一个项目管理的工具,可以对项目进行构建、依赖的管理。我们只需要告诉Maven需要哪些Jar 包,它会帮助我们下载所有的Jar,极大提升开发效率
4.1.1 Maven与IDEA版本对应表
注意:针对一些老项目 还是尽量采用 3.6.3版本,针对idea各个版本的兼容性就很兼容
0.IDEA 2022 兼容maven 3.8.1及之前的所用版本
1.IDEA 2021 兼容maven 3.8.1及之前的所用版本
2.IDEA 2020 兼容Maven 3.6.3及之前所有版本
3.IDEA 2018 兼容Maven3.6.1及之前所有版本
4.2 Maven安装
-
下载地址:https://maven.apache.org/download.cgi
-
环境变量配置
-
添加MAVEN_HOME ,其对应的值为
-
将MAVEN_HOME 添加到PATH中去
-
环境变量配置完测试
-
4.3 添加阿里云镜像
mirrors:加速下载
<mirror>
<id>central</id>
<name>central</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
添加到conf–>settings.xml中去
4.4 本地仓库
<localRepository>E:\JavaWeb\Maven\apache-maven-3.9.1\maven-repo </localRepository>
建立一个本地仓库 localRepository 【改地址了:D:\Skill\JavaWeb\Maven\apache-maven-3.6.3\maven-repo】
4.5 在IDEA中使用MAVEN
- 创建maven项目
-
观察maven仓库中多了什么?
-
在idea中配置maven【idea项目创建时需要注意这个位置】
-
4.6 问题
-
解决Maven 在pom.xml的build中配置resources,来防止我们资源导出失败的问题
<build> <resources> <resource> <!-- 设定主资源目录 --> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
5.servlet
5.1 servlet 简介
servlet 是sun 公司开发动态web的一项技术。
servlet有两个实现类:HttpServlet,GenericServlet
sun在API【应用程序接口】上提供了一个接口sevlet,开发servlet程序的步骤。
- 编写一个实现了servlet接口的java程序。
- 把开发好的java类部署到web 服务器上。
servlet:实现了servlet接口的java程序。
5.2 HelloServlet
操作流程:创建一个普通的maven项目-----删除src目录------在父项目中创建一个带有web的maven项目
在子项目中的操作
- 创建java类实现servlet接口
package com.lumos.servlet;
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 HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter(); // 相应流
writer.write("Welcome To Servlet!");
writer.print("HHHHHHHH----HHHHHH");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
- 编写Servlet映射
为什么需要映射:我们所写的是java程序,需要通过浏览器来访问程序,而浏览器需要连接web服务器,所以需要在web服务器中注册我们所写的servlet,还需要给一个浏览器访问的路径
<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"> <!-- 注册servlet --> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.lumos.servlet.HelloServlet</servlet-class> </servlet> <!-- servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
- 配置Tomcat
-
启动与测试
启动Tomcat即可—自动打开网站【访问】自己写的程序需要在后面加上面映射的/hello,不加则是默认页面
问题
问题1:子项目中没有出现src目录
解决方法:添加 -Darchetype=Internal 这条语句,然后重新创建子项目
- 问题2:解决tomcat控制台是乱码的问题
将UTF-8 设置为GBK就可以了
5.3 Servlet原理
5.4 映射Mapping 注意事项
优先级问题:有特定的匹配则优先匹配,没有则默认匹配【按照通配符】
-
一个servlet对应一个映射路径
<!-- servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
一个servlet对应多个映射路径
<!-- servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <!-- servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello2</url-pattern> </servlet-mapping> <!-- servlet的请求路径 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello3</url-pattern> </servlet-mapping>
-
一个servlet对应通用映射路径
<!-- servlet的请求路径 【一个servlet对应通配 映射路径】 --> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello/*</url-pattern> </servlet-mapping>
-
一个servlet对应默认的映射路径【不管输入什么都会映射到hello】
<!-- servlet的请求路径 【一个servlet对应一个映射路径】 -->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
- 一个servlet对应指定前缀或指定后缀 映射路径
<!-- servlet的请求路径 【一个servlet对应特定结尾映射路径】 -->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<!-- *.linxiaojun 表示必须以.linxiaojun结尾 -->
<url-pattern>*.linxiaojun</url-pattern>
</servlet-mapping>
-
定义错误网址所导向类
<!-- servlet的请求路径 【错误路径导向ErrorServlet类中】 --> <servlet> <servlet-name>Error</servlet-name> <servlet-class>com.lumos.servlet.ErrorServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Error</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
package com.lumos.servlet; 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 ErrorServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); PrintWriter writer = resp.getWriter(); writer.write("<h1>This is 404 Error From ErrorServlet!</h1>"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
5.5 ServletContext
-
什么是ServletContext
是基于Web容器和Servlet之间的中间件,可以对下面的Servlet进行管理;Web容器在启动的时候,会为每个应用程序创建一个相对应的ServletContext对象,其代表了当前的应用
-
作用
数据共享:不同servlet之间可以通信【getServletContext】
HelloServlet类
public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("hello"); ServletContext context = this.getServletContext(); String username = (String) context.getAttribute("username"); resp.setContentType("text/html;charset=utf-8"); //这句话相当于下面两条语句;用于设置编码格式 // resp.setContentType("text/html"); // resp.setCharacterEncoding("utf-8"); resp.getWriter().write("name : "+username); } }
GetContext类
public class GetContext extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); //获取对象ServletContext context.setAttribute("username","林小军"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
**web.xml**
<servlet> <servlet-name>hello</servlet-name> <servlet-class>com.lumos.servlet.HelloServlet</servlet-class> <!-->对应数据类HelloServlet<--> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello00</url-pattern> </servlet-mapping> <!-->向serverletContext中存储数据<--> <servlet> <servlet-name>gc</servlet-name> <servlet-class>com.lumos.servlet.GetContext</servlet-class> <!-->对应数据类GetContext<--> </servlet> <servlet-mapping> <servlet-name>gc</servlet-name> <url-pattern>/getname</url-pattern> </servlet-mapping> </web-app>
测试结果:
- 获取初始化参数【getInitParameter】
GetServletParameters类
public class GetServletParameters extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); String url = context.getInitParameter("url"); resp.getWriter().write(url); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
Web.xml
<!-- 自定义参数 --> <context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/test</param-value> </context-param> <!-- ServletContext获取参数 --> <servlet> <servlet-name>getPars</servlet-name> <servlet-class>com.lumos.servlet.GetServletParameters</servlet-class> </servlet> <servlet-mapping> <servlet-name>getPars</servlet-name> <url-pattern>/gp</url-pattern> </servlet-mapping>
测试结果
- 请求转发与重定向【getRequestDispatcher】
RequestDispatcher类
public class RequestDispatcher extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); //获取对象ServletContext // 将请求转发到/gp下,也就是GetServletParameters; javax.servlet.RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp"); requestDispatcher.forward(req,resp); System.out.println("进入了请求转发类。。。"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
web.xml
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>com.lumos.servlet.RequestDispatcher</servlet-class> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/dispatcher</url-pattern> </servlet-mapping>
测试结果
-
获取配置文件
【resources和java 目录下的配置文件都是在classess目录下 getResouceAsStream()】
db.properties文件
username=root password=123 driver=jdbc:mysql://localhost:3306/test
public class GetServletProperties extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Properties prop = new Properties(); //下面这条语句是重点-----主要是获取流对象 ----从生成的target中进行获取! InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); prop.load(resourceAsStream); String name = prop.getProperty("username"); String pwd = prop.getProperty("password"); resp.getWriter().write("username: "+name+"\tpwd: "+pwd); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
web.xml
<servlet> <servlet-name>prop</servlet-name> <servlet-class>com.lumos.servlet.GetServletProperties</servlet-class> </servlet> <servlet-mapping> <servlet-name>prop</servlet-name> <url-pattern>/prop</url-pattern> </servlet-mapping>
测试结果
5.6 HttpServletResponse
Web服务器接受来自浏览器或客户端的HTTP请求,针对这个请求,服务器分别创建了代表请求的HttpServletRequest,以及代表响应的HttpServletResponse;
-
response 向浏览器发送响应的方式
ServletOutputStream out = resp.getOutputStream(); //图片,文件,视频用这个 PrintWriter writer = resp.getWriter(); //写中文,或文本用这个 ,错误使用可能导致信息传输不完-整
-
HttpServletResponse中方法
void setDateHeader(java.lang.String s, long l); void addDateHeader(java.lang.String s, long l); void setHeader(java.lang.String s, java.lang.String s1); void addHeader(java.lang.String s, java.lang.String s1); void setIntHeader(java.lang.String s, int i); void addIntHeader(java.lang.String s, int i); void setStatus(int i);
3.HttpServletResponse中状态码
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
- 常见应用
-
- 下载文件功能
> * //核心代码
> //3.设置浏览器能支持 Content-Disposition 来下载我们所需要的东西
> *resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));*
package com.lumos.servlet;
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.net.URLEncoder;
/**
* @Date : 2023-05-15 18:08
* @Author : linxiaojun
* @Desc : response-----文件下载【Content-Disposition,attachment;filename=】
* @En :
* @Att : 与底层的java输入输出流息息相关
*/
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.文件下载的路径
String filepath = "F:\\学科\\程序课程\\java\\Project\\JavaWeb\\javaweb-02-HelloServlet\\response\\src\\main\\resources\\code.txt";
System.out.println("下载的路径:" + filepath);
//2.获取文件的文件名
String filename = filepath.substring(filepath.lastIndexOf("\\") + 1);
//3.设置浏览器能支持 Content-Disposition 来下载我们所需要的东西,URLEncoder.encode(filename, "utf-8")可将汉字转化为UTF-8格式
resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "utf-8"));
// 4.创建输入流
FileInputStream fis = new FileInputStream(filepath);
//5.创建输出流
ServletOutputStream out = resp.getOutputStream();
int len = 0;
byte[] buffer = new byte[1024];
//6.将读取的数据信息写入到response中去
while ((len = fis.read(buffer)) > 0)
out.write(buffer, 0, len);
fis.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
结果验证:
-
**验证码功能 ** [
-
//将BufferedImage图像保存在本地计算机 BufferedImage image=new BufferedImage(wid,hei,BufferedImage.TYPE_INT_RGB); File file = new File("output.png"); //保存的目录地址 boolean png = ImageIO.write(image, "png", file); //图像对象,后缀名,文件路径-->决定写在哪里
-
]
//清除浏览器的缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
package com.lumos.servlet;
import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Random;
/**
* @Date : 2023-05-15 20:11
* @Author : linxiaojun
* @Desc : response实现验证码功能
* @En :
* @Att :
*/
public class ImageServlet extends HttpServlet {
static String[] strs={"a","b","c","d","e","f","g","h","i","j","k","m","n",
"o","p","q","r","s","t","u","v","w","x","y","z","2","3","4","5","6","7","8","9"};
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//让浏览器3s自动刷新一次
resp.setHeader("refresh","3");
//设置浏览器打开页面的格式
resp.setContentType("image/png");
//不让浏览器存在缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
int wid=150;//定义图片宽度
int hei=50;//定义图片高度
int x=25,y=35;
Random random=new Random();
//1.画板
BufferedImage image=new BufferedImage(wid,hei,BufferedImage.TYPE_INT_RGB);
//2.获取画笔的对象
Graphics g=image.getGraphics();
//3.设置画笔参数
g.setColor(Color.white);//设置填充颜色
g.fillRect(0,0,wid,hei);//填充矩形,覆盖原矩形
g.setColor(Color.red);//重新填充
g.setFont(new Font("楷体",Font.BOLD,25));
//4.画数字
for (int i = 0; i <4; i++) {
int num=random.nextInt(strs.length);
g.drawString(strs[num],x,y);
x+=30;
}
//5.画干扰线
for (int i = 0; i <3 ; i++) {
int x1=random.nextInt(30);
int y1=random.nextInt(50);
int x2=random.nextInt(30)+100;
int y2=random.nextInt(50);
g.drawLine(x1,y1,x2,y2);
}
//直接将验证码输出到浏览器
ImageIO.write(image,"png", resp.getOutputStream());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
结果验证:
-
重定向功能
URL路径会发生改变
关键代码
resp.sendRedirect("./IdentifyingCode");
实现代码
package com.lumos.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @Date : 2023-05-17 10:05 * @Author : linxiaojun * @Desc : 实现重定向 * @En : * @Att : 区别重定向与请求转发的区别 */ public class RedirectServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.sendRedirect("./IdentifyingCode"); //需要用.表示当前项目下 } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
结果验证:
5.7 HttpServletRequest
- 一个是请求转发
- 一个是获取参数
-
重定向和转发的区别?
-
相同点:都能跳转页面
-
不同点:请求转发的时候,URL不会发生变化 307
重定向的时候,URL会发生变化 302
-
package com.lumos.servlet;
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.Arrays;
/**
* @Date : 2023-05-18 10:31
* @Author : linxiaojun
* @Desc :request 实现用户登录,登录成功后跳转到成功的页面
* @En :
* @Att :
*/
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println(username+":"+password+"\n"+ Arrays.toString(hobbies));
//请求转发到另一个界面
req.getRequestDispatcher("./success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
6. Cookie && Session
6.1 什么是会话?
会话:用户打开一个浏览器,在浏览器中点开n多超链接,然后关闭浏览器,这个过程可以称之为会话
有状态会话:来过一次后续就知道该同学来过
6.2 实现会话的两种技术
- Cookie:应用于客户端
- Session:应用于服务端
6.3 Cookie
Tip
- 服务器响应客户端cookie
- 一般保存在本地用户appdata目录下
- 一个cookie最多保存一个信息,最多发送20个cookie
- 每一个cookie大小限制为4kb
- 300个cookie浏览器上限
删除cookie
- 不设置cookie有效期 【关闭浏览器时cookie自动删掉】
- 设置cookie有效期为0【cookie.setMaxAge(0)】
编码和解码的问题
URLEncoder.encode("abc","utf-8") URLDecoder.decode("abc","utf-8")
package com.lumos.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
/**
* @Date : 2023-05-18 11:54
* @Author : linxiaojun
* @Desc : cookie的使用
* @En :
* @Att : 1.编码和解码的问题
* URLEncoder.encode("abc","utf-8")
* URLDecoder.decode("abc","utf-8")
* 2. cookie是键值对
* 3.解决中文乱码:req.setCharacterEncoding("utf-8")
resp.setCharacterEncoding("UTf-8");
resp.setHeader("Content-Type","text/html;charset=utf-8");
*/
public class cookieDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取cookie对象
Cookie[] cookies = req.getCookies();
for (int i = 0; i < cookies.length; i++) {
System.out.println(cookies[i]);
if (cookies != null) {
if (cookies[i].getName().equals("lastLoginTime")) {
//输出时间
Long time = Long.parseLong(cookies[i].getValue());
Date date = new Date(time);
resp.getWriter().write("\nLast Login Time:" + date.toLocaleString());
}
} else {
resp.getWriter().write("This is your first time come here!\n");
}
Cookie ck = new Cookie("lastLoginTime", "" + System.currentTimeMillis());
ck.setMaxAge(1000); // 设置有效时间【保存在浏览器的时间】
resp.addCookie(ck);//添加cookie
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
6.4 Session
- 什么是session?
- 服务器会为每个浏览器创建一个session对象,存在周期为只要浏览器未关闭即存在,且一个session独占一个浏览器
- 配置session失效时间
<!-- 使用配置文件来配置session失效时间 -->
<session-config>
<!-- 配置默认失效时间,以分钟为单位 -->
<session-timeout>1</session-timeout>
</session-config>
- 手动注销session
package com.lumos.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @Date : 2023-05-18 20:56
* @Author : linxiaojun
* @Desc : 手动注销session
* @En :
* @Att :
*/
public class SessionDemo4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//防止编码错误
req.setCharacterEncoding("utf-8");
resp.setContentType("utf-8");
resp.setContentType("text/html;charset=utf-8");
//获取session
HttpSession session = req.getSession();
//手动配置session失效
session.removeAttribute("name");
session.invalidate();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
6.5 session 与 cookie的区别?
- cookie是把数据存储到用户的浏览器中,浏览器可以同时保存多个
- session 是把数据存储到用户独占的session中,服务器端保存
servletContext【ApplicationContext】可以使不同session用户进行访问
7.JSP
7.1 什么是JSP
JSP:JAVA Server Pages java服务器端页面,与servlet一样,用于动态web技术
特点:可以在jsp中嵌套java语言,与写HTML类似
7.2 JSP原理
7.3 环境搭建【添加依赖】
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>javaweb-04-jsp</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<!-- servlet依赖-->
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!-- servlet.jsp依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!-- 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>
</dependencies>
</project>
7.4 JSP语法
-
JSP表达式1
<%-- 1.jsp表达式,作用: 取值输出到客户端 --%> <%=new Date()%>
-
JSP代码片段2
<%-- 2.jsp脚本片段 --%> <% int sum=0; for (int i = 0; i < 10; i++) { sum+=i; } out.print("和为:"+sum); %>
-
JAVA代码中嵌入HTML
<%-- 2.1.在java代码中嵌入html --%> <% for (int i = 0; i < 10; i++) { %> <h1 align="center">hello , world <%=i%> </h1> <%}%>
-
JSP 的全局声明3:需要加!,jsp声明会被编译到java类中,而其他的都被编译到service方法中
<%--3.jsp全局声明--%> <%! static { System.out.println("进入了静态块中"); } private int count=0; public void test(){} %>
-
注释【jsp注释不会显示,html注释会显示】
-
7.5 JSP指令
- 定制错误页面<%@page args %>
2.include :包含文件
使用<%@include file=args %> 是把引入的文件合成一个【三个文件合成一个】
<%@include file="header.jsp"%>
<h1>这是网站主题</h1>
<%@include file="footer.jsp"%>
采用jsp的方式是将引入的文件作为一个独立的文件处理的【三个文件为三个】
<jsp:include page="header.jsp"></jsp:include>
<h1>This is the body of webside</h1>
<jsp:include page="footer.jsp"></jsp:include>
7.6 九大内置对象 【作用域】
-
PageContext 【可存东西】
-
Request 【可存东西】
-
Response
-
Session 【可存东西】
-
Application 【可存东西】
-
Config
-
out
-
Page
-
Exception
实现代码
<%--
Created by IntelliJ IDEA.
User: lin
Date: 2024/1/6
Time: 16:28
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>
<%
pageContext.setAttribute("name1","李学年1"); //请求的数据在当前页面有效
request.setAttribute("name2","李学年2");//请求的数据在一次请求中有效,请求转发时会携带这个数据
session.setAttribute("name3","李学年3");//请求的数据在一次会话中有效,也就是打开浏览器到关闭
application.setAttribute("name4","李学年4");//请求的数据在整个服务器中 有效,服务器的打开到关闭
//可以按照下面的方法【利用最后一个参数的不同】来代替上面的方法
// pageContext.setAttribute("name4","abc",PageContext.APPLICATION_SCOPE);
%>
<%
//取值方式1;
String n1 = (String) pageContext.findAttribute("name1");
String n2 = (String) pageContext.findAttribute("name2");
String n3 = (String) pageContext.findAttribute("name3");
String n4 = (String) pageContext.findAttribute("name4");
%>
<%--取值方式二:正则表达式--%>
<h1>${name1}</h1>
<h1>${name2}</h1>
<h1>${name3}</h1>
<h1>${name4}</h1>
<h1>${name5}</h1>
</body>
</html>
转发方式
<%
//前端转发
pageContext.forward("index.jsp");
//后端转发request.getRequestDispatcher("index.jsp").forward(request,response);
%>
7.7 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>
-
EL标签【${}】作用:
- 获取数据
- 执行运算
- 获取web开发对象
-
JSP 标签
<h1>This is jspTag pages</h1> <% 应用1:Include包含文件 应用2:forword转发 应用3:携带参数 %> <jsp:forward page="context.jsp"> <jsp:param name="name" value="female"/> <jsp:param name="age" value="12"/> </jsp:forward> <jsp:include page="common/head.jsp"/> <%//取参数%> <%=request.getParameter("name")%> <%=request.getParameter("age")%>
-
JSTL标签
JSTL标签库的组成部分
>核心标签库: core, 简称c
>格式化标签库: format, 简称fmt
>函数标签库: function, 简称fn
核心标签【掌握部分这个就ok】
核心标签库导入的语句为: <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
-
TIP:在tomacat的lib目录下也需要导入standard和jstl的jar包
-
c_foreach
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page import="java.util.ArrayList" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <% ArrayList<String> list = new ArrayList<>(); list.add("李四"); list.add("张三"); list.add("王五"); list.add("赵六"); list.add("六七"); request.setAttribute("lis",list); %> <%--********* --%> <c:forEach var="abc" items="${lis}" begin="1" step="2"> <c:out value="${abc}"/><br> </c:forEach> </body> </html>
-
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</title> </head> <body> <h3>This is jstlCore test pages</h3> <form action="jstlCore.jsp" method="get"> <%--${param.username}el表达式获取对象--%> <input name="username" value="${param.username}"> <input type="submit" value="submit"> </form> <c:if test="${param.username=='admin'}" var="isAdmin"> <c:out value="YES,admin 欢迎你 "/> </c:if> <%--自闭合标签--%> <c:out value="${isAdmin}"/> </body> </html>
-
-
7.8 servlet 与JSP的异同点
序号 | servlet | JSP |
---|---|---|
1 | 是在java中嵌套html代码,支持html标签 | 在html中嵌套java代码,支持java语言 |
2 | 用于业务层处理逻辑 | 用于展示层显示数据 |
3 | 修改后需重新编译部署 | 修改后不需重新编译以及运行 |
8.MVC三层架构
8.1 什么是MVC
model【包含entity,dao,service,操作】 view【展示】 controller【中间件】
9.Filter过滤器
9.1 什么是过滤器?
用来过滤网站中的数据
- 处理字符的乱码
- 登录验证
- 处理垃圾请求
开发步骤
-
导包
-
实现接口
package com.lumos.filter; import javax.servlet.*; import java.io.IOException; /** * @Date : 2023-05-21 18:38 * @Author : linxiaojun * @Desc : filter实现请求自动编码 */ public class CharEncodingFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { System.out.println("filter 初始化"); } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { servletRequest.setCharacterEncoding("utf-8"); servletResponse.setCharacterEncoding("utf-8"); servletResponse.setContentType("text/html;charset=UTF-8"); System.out.println("filter执行前"); filterChain.doFilter(servletRequest,servletResponse); //*****这句话是关键 System.out.println("filter执行后"); } public void destroy() { System.out.println("filter销毁"); } }
web.xml注册filter <filter> <filter-name>charEncodingFilter</filter-name> <filter-class>com.lumos.filter.CharEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>charEncodingFilter</filter-name> <url-pattern>/servlet/*</url-pattern> </filter-mapping>
-
过滤器实现用户输入正确密码后进入success页面,注销后,不可访问success页面,未注销可访问【注意路径问题】
效果图
jsp代码
login.jsp
<html>
<%@page contentType="text/html; charset=utf-8" language="java" %>
<body>
<form method="post" action="./login1">
用户名:<input type="text" name="username">
<input type="submit" value="submit">
</form>
</body>
</html>
success.jsp【注意success.jsp是在sys目录下的】
<html>
<%@page contentType="text/html; charset=utf-8" language="java" %>
<body>
<p> 登录成功啦</p>
<%--<a href="login.jsp">点击注销</a>--%>
<form method="post" action="../logout">
<input type="submit" value="logout">
</form>
</body>
</html>
false.jsp
pjsp<html>
<%@page contentType="text/html; charset=utf-8" language="java" %>
<body>
<p>登录失败</p>
<a href="login.jsp">点击重新登录</a>
</body>
</html>
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>showServlet</servlet-name>
<servlet-class>com.lumos.servlet.ServletDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>showServlet</servlet-name>
<url-pattern>/servlet/showServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>showServlet</servlet-name>
<url-pattern>/show</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.lumos.servlet.Login</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>logout</servlet-name>
<servlet-class>com.lumos.servlet.Logout</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>logout</servlet-name>
<url-pattern>/logout</url-pattern>
</servlet-mapping>
<filter>
<filter-name>CharacterEncoding</filter-name>
<filter-class>com.lumos.filter.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncoding</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.lumos.filter.Filter2</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/sys/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.lumos.listener.Listener_</listener-class>
</listener>
</web-app>
logout.java
package com.lumos.servlet;
import com.lumos.constant.Con_;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @CreateDate: 2024/1/6 20:28
* @Description:
* @English:
* @Author: lin
*/
public class Logout extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object attribute = req.getSession().getAttribute(Con_.USER_SESSION);
if(attribute!=null){
req.getSession().removeAttribute(Con_.USER_SESSION);
resp.sendRedirect("login.jsp");
}else resp.sendRedirect("login.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
login.java
package com.lumos.servlet;
import com.lumos.constant.Con_;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @CreateDate: 2024/1/6 20:24
* @Description:
* @English:
* @Author: lin
*/
public class Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
if(username.equals("admin1")){
req.getSession().setAttribute(Con_.USER_SESSION,req.getSession().getId());
resp.sendRedirect("./sys/success.jsp");
}else resp.sendRedirect("./false.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
filter.java
package com.lumos.filter;
import com.lumos.constant.Con_;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @CreateDate: 2024/1/6 20:58
* @Description:
* @English:
* @Author: lin
*/
public class Filter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req= (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if(req.getSession().getAttribute(Con_.USER_SESSION)==null){
resp.sendRedirect("../false.jsp");
}
chain.doFilter(req,resp);
}
@Override
public void destroy() {
}
}
10.监听器
实现步骤
-
实现接口
package com.lumos.listener; import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; /** * @Date : 2023-05-21 19:35 * @Author : linxiaojun * @Desc :使用HTTPSessionListener监听器在网站中统计在线人数 * @En : * @Att : */ public class OnlinePeopleCount implements HttpSessionListener { public void sessionCreated(HttpSessionEvent hse) { ServletContext sc = hse.getSession().getServletContext(); System.out.println(hse.getSession().getId()); Integer count = (Integer) sc.getAttribute("OnlinePeopleCount"); if(count==null){ count=new Integer(1); }else{ int i = count.intValue(); count=new Integer(i+1); } sc.setAttribute("OnlinePeopleCount",count); } public void sessionDestroyed(HttpSessionEvent hse) { ServletContext sc = hse.getSession().getServletContext(); System.out.println("销毁:"+hse.getSession().getId()); Integer count = (Integer) sc.getAttribute("OnlinePeopleCount"); if(count==null){ count=new Integer(0); }else{ int i = count.intValue(); count=new Integer(i-1); } hse.getSession().invalidate(); sc.setAttribute("OnlinePeopleCount",count); } }
-
web.xml中配置
<listener> <listener-class>com.lumos.listener.OnlinePeopleCount</listener-class> </listener>
-
11.smbms
JSONArray.toJSONString(map)//将map转化为json数据【利用FastJson】
按钮点击跳转的方式
<a href="./download">
<button>下载</button>
</a>
<button onclick="window.location.href='./download'" type="button" id="add">download</button>
</body>
12.文件上传
参考链接https://www.cnblogs.com/yayuya/p/16082761.html
12.1 导入网络传输的包
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.0</version>
</dependency>
js包
<dependency>
<!-- servlet依赖-->
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!-- servlet.jsp依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!-- 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>
12.2 文件上传的注意事项
- 保证服务器安全,上传的文件应该放在外界无法访问的目录下,如WEB-INF目录下
- 为防止上传文件覆盖的情况,需要为每个上传的文件设置一个独立的文件名或者id
- 限制上传文件的数量
- 限制上传文件的类型,即判断文件是否合法
12.3代码
package com.lumos.servlet;
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;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
/**
* @CreateDate: 2024/1/13 0:20
* @Description:
* @English:
* @Author: lin
*/
public class uploadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//判断上传的文件是普通表单还是带文件的表单,两者有区别,文件的要传输,普通的表单收取字符串
if (!ServletFileUpload.isMultipartContent(req)) {//是否包含文件
return;//不是,终止方法运行,说明这个一个普通的表单,直接返回
}//如果通过了这个if,说明我们的表单是带文件上传的
//创建上传文件的保存路径,建议在WEB-INF路径下,安全,用户无法直接访问上传的文件;
String uploadPath = this.getServletContext().getRealPath("WEB-INF/upload");//获得:全局上下文.真实地址
//判断这个文件有没有
File uploadFile = new File(uploadPath);
if (!uploadFile.exists()) {//如果文件不存在
uploadFile.mkdir();//创建这个目录
}
/*
缓存:临时文件 tmp
文件上传速度太慢了,给他个中间商,慢慢上传,保证是匀速进来的
*/
//临时路径,假设文件超过了预期的大小,我们就把他放到一个临时文件中,过几天自动删除,或者提醒用户转存为永久
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组件
/*
流程:
ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个Fileltem对象,
在使用ServletFilelpload对象(上传)解析请求时,需要DiskFileltemFactory对象。
所以,我们需要在进行解析工作前构造好DiskFileltemFactory对象,
通过SevletFileUpload对象的构造方法或setFileltemFactory()方法
设置ServletFileUpload对象的fileltemFactory属性。
*/
try {
/*核心代码:处理这几个类*/
//1.创建 DiskFileItemFactory(磁盘工厂)对象,处理文件上传路径或者大小限制
DiskFileItemFactory factory = getDiskFileItemFactory(file);
//2.获取 ServletFileUpload
ServletFileUpload upload = getServletFileUpload(factory);//把 factory 类作为参数传递进来
//3.处理上传的文件
String msg = uploadParseRequest(upload, req, uploadPath);
//servlet请求转发消息
req.getSession().setAttribute("msg", msg);
req.getRequestDispatcher("info.jsp").forward(req, resp);
} catch (FileUploadException e) {
e.printStackTrace();
}
}
public static DiskFileItemFactory getDiskFileItemFactory(File file) {
DiskFileItemFactory factory = new DiskFileItemFactory();
//通过这个工厂设置一个缓存区,当上传的文件大于这个缓冲区的时候,将他放入到临时文件中
factory.setSizeThreshold(1024 * 1024);//缓冲区为1M
factory.setRepository(file);//临时目录的保存目录,需要一个File
return factory;
}
public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
ServletFileUpload upload = new ServletFileUpload(factory);
//监听文件的上传进度
upload.setProgressListener(new ProgressListener() {
@Override
//pBytesRead:已经读取到的文件大小
//pContentLength:文件大小
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("总大小:" + pContentLength + "已上传:" + pBytesRead);
}
});
//处理乱码问题
upload.setHeaderEncoding("UTF-8");
//设置单个文件的最大值
upload.setFileSizeMax(1024 * 1024 * 10);
//设置总共能够上传文件的大小
//1024 = 1kb * 1024 = 1M * 10 = 10M
upload.setSizeMax(1024 * 1024 * 10);
return upload;
}
public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath) throws IOException, FileUploadException, FileUploadException {
String msg = "";
//3.把前端请求解析,封装成一个FileItem对象,需要从ServletFileUpload对象中获取
List<FileItem> fileItems = upload.parseRequest(request);
//fileItem 每一个表单对象
for (FileItem fileItem : fileItems) {
//判断上传的文件(控件)是普通的表单还是带文件的表单,判断是不是 input file
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);//最后一个 / +1
//获得文件的后缀名
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
/*
如果文件后缀名 fileExtName 不是我们需要的,
就直接return,不处理,告诉用户文件类型不对。
*/
System.out.println("文件信息[件名:" + fileName + "---文件类型" + fileExtName + "]");
/*面试题
网络传输中的东西,都需要序列化
POJO,实体类,如果想要在多个电脑上运行, 需要:传输==>把对象都序列化了
写POJO实体类时,把这个接口 implements Serializable 加上 ,标记接口(没有方法的接口)
标记接口:java虚拟机(JVM)在运行到的时候,它去识别,假设实现了 Serializable 这个接口,会帮你做一些事情。
JVM中有一个本地方法栈:native,它是调用C++的,java虚拟机底层是C++写的。
JNI = Java Native Interface java本地化接口,
java是无法操作计算机的,java是操作JVM的,JVM操作计算机(操作系统)
JVM中还有一个java栈,平时写东西在java栈中写,本地方法栈是C++做的、操作系统来做
公司里常用UUID,这个安全
*/
//可以使用UUID(唯一识别的通用码),保证文件名唯一
//UUID.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();
//创建一个文件输出流
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;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
13.邮件发送
参考连接:https://blog.csdn.net/weixin_52093131/article/details/121958148
13.1对象关系
13.2 导入对用的包
13.3
邮件分为
-
简单邮件:纯文本,没有附件和图片
package com.lumos; import com.sun.mail.util.MailSSLSocketFactory; import javax.mail.*; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.util.Properties; /** * @CreateDate: 2024/1/15 13:11 * @Description: 简单邮件发送【只涉及文本】 * @English: * @Author: lin */ // 授权码:oyvawtjctoetgdhg /* * 实现步骤 1.创建session对象 2.创建Transport对象 3.使用邮箱的用户名和授权码连上邮件服务器 4.创建一个Message对象(需要传递session)message需要指明发件人、收件人以及文件内容 5.发送邮件 6.关闭连接 * */ public class Mail { 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");//需要验证用户密码 prop.put("mail.smtp.ssl.protocols", "TLSv1.2"); //端口 prop.setProperty("mail.smtp.port", "465"); //QQ邮箱需要设置SSL加密【qq独有】 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对象 Session session = Session.getDefaultInstance(prop, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("1350048132@qq.com", "oyvawtjctoetgdhg"); } }); //开启session的debug模式,这样可以查看到程序发送Email的运行状态 session.setDebug(true); //2.通过session得到transport对象 Transport ts = session.getTransport(); //3.使用邮箱的用户名和授权码连上邮件服务器 ts.connect("smtp.qq.com", "1350048132@qq.com", "oyvawtjctoetgdhg"); //4.创建邮件:写文件 //注意需要传递session MimeMessage message = new MimeMessage(session); //指明邮件的发件人 message.setFrom(new InternetAddress("1350048132@qq.com")); //指明邮件的收件人 message.setRecipient(Message.RecipientType.TO, new InternetAddress("1547438538@qq.com")); //邮件标题 message.setSubject("邮件测试" + "--来自Java"); //邮件的文本内容 message.setContent("你好哇", "text/html;charset=UTF-8"); //5.发送邮件 ts.sendMessage(message, message.getAllRecipients()); //6.关闭连接 ts.close(); } }
-
复杂邮件:有附件和图片
//在上述基础上增加了附件与图片代码段
message.setSubject("邮件测试带图片" + "--来自Java");
//=================================准备图片数据=======================================
MimeBodyPart image=new MimeBodyPart();
//图片需要经过数据化的处理
DataHandler dh=new DataHandler(new FileDataSource("D:\\Skill\\Project\\mavenLearn\\功能扩展\\mail-java\\src\\富士山.jpg"));
//在part中放入这个处理过图片的数据
image.setDataHandler(dh);
//给这个part设置一个ID名字
image.setContentID("bz.jpg");
//准备正文的数据
MimeBodyPart text=new MimeBodyPart();
text.setContent("这是一张正文<img src='cid:bz.jpg'>","text/html;charset=UTF-8");
//描述数据关系
MimeMultipart mm=new MimeMultipart();
mm.addBodyPart(text);
mm.addBodyPart(image);
mm.setSubType("related");
//设置到消息中,保存修改
message.setContent(mm);
message.saveChanges();
14.使用邮件实现注册功能
用户注册后发送给用户邮件一封信息【可以扩展为用户注册,用户忘记密码后找回密码】
RegServlet
package com.lumos.servlet;
import com.lumos.entity.User;
import com.lumos.utils.SendMail;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @CreateDate: 2024/1/15 14:58
* @Description: SERVLET接受前端参数,异步发送邮件
* @English:
* @Author: lin
*/
public class RegMailServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String mail = req.getParameter("mail");
//把用户的请求封装成一个对象
User user = new User(username,password,mail);
//启动线程,重定向页面
/*
用户注册成功后,给用户发送一封邮件
我们使用线程来专门发送邮件,防止出现耗时、白屏和网站注册人数过多的情况
*/
SendMail send = new SendMail(user);
send.start();
//注册用户
req.setAttribute("message","注册成功,我们已经发了一封要了注册信息的电子邮件,请查收!如网络不稳定,请稍等");
req.getRequestDispatcher("info.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
SendMail异步发送邮件工具类
package com.lumos.utils;
/**
* @CreateDate: 2024/1/15 15:08
* @Description: 异步处理发送邮件,提高用户体验
* @English:
* @Author: lin
*/
import com.lumos.entity.User;
import com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
/*
网站3秒原则:用户体验
让用户不等待,事情也还做?
用户执行完这个方法,它还走它的东西,我走我的页面
通过多线程,实现用户体验!(异步处理)
*/
public class SendMail extends Thread{
//用于给用户发送邮件的邮箱
private String from = "1350048132@qq.com" ;
//邮箱的用户名
private String username = " 1350048132@qq.com" ;
//邮箱的密码
private String password = "oyvawtjctoetgdhg";
//发送邮件的服务器地址
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();
prop.setProperty("mail.host",host);///设置QQ邮件服务器
prop.setProperty("mail.transport.protocol","smtp");///邮件发送协议
prop.setProperty("mail.smtp.auth","true");//需要验证用户密码
prop.put("mail.smtp.ssl.protocols", "TLSv1.2");
//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对象
Session session= Session.getDefaultInstance(prop, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(from,password);
}
});
//开启session的debug模式,这样可以查看到程序发送Email的运行状态
session.setDebug(true);
//2.通过session得到transport对象
Transport ts = session.getTransport();
//3.使用邮箱的用户名和授权码连上邮件服务器
ts.connect(host,username,password);
//4.创建邮件:写文件
//注意需要传递session
MimeMessage message = new MimeMessage(session);
//指明邮件的发件人
message.setFrom(new InternetAddress(from));
//指明邮件的收件人
message.setRecipient(Message.RecipientType.TO,new InternetAddress(user.getMail()));//从前端接收的
//邮件标题
message.setSubject("注册通知");
//邮件的文本内容
String info = "恭喜你("+user.getUsername()+")成功注册!"+"密码:"+user.getPassword();
message.setContent(info,"text/html;charset=UTF-8");
message.saveChanges();//保存更改
//5.发送邮件
ts.sendMessage(message,message.getAllRecipients());
//6.关闭连接
ts.close();
}catch (Exception e){
System.out.println(e);
}
}
}
前端页面index.jsp
<%@page contentType="text/html;charset=utf-8"%>
<html>
<head><title>Mail Register</title></head>
<body>
<span style="text-align: center"><h2>Mail Reg</h2></span>
<div style="text-align: center">
<form action="./reg" method="post">
用户名:<input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
邮箱:<input type="text" name="mail" >
<input type="submit" value="注册">
</form>
</div>
</body>
</html>
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>regMail</servlet-name>
<servlet-class>com.lumos.servlet.RegMailServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>regMail</servlet-name>
<url-pattern>/reg</url-pattern>
</servlet-mapping>
</web-app>