文章目录
- Java Web 02
- 一、Servlet基本流程
- 二、Servlet
- 1、Servlet 接口
- 1)Servlet简介
- 2)Servlet原理
- 抽象方法
- 2、GenericServlet 抽象类
- 两个init()方法==重点==
- 3、HttpServlet 抽象类
- 重写方法,不能使用super
- 两个service()方法==重点==
- 4、Mapping 映射路径
- 1)servlet与mapping映射路径的多个情况
- 2)映射路径的优先级
- 5、ServletContext 接口对象
- 常用方法
- 请求转发与重定向的区别 ==重点==
- 6、HttpServletRequest 接口
- 获取前端的参数
- 请求转发
- 7、HttpServletResponse 接口
- 浏览器下载文件
- 验证码实现
- 重定向 ==(重要)==
- 三、Cookie 类
- 四、Session 接口 ==(重点)==
- Cookie 与 Session 的区别与联系 ==重点==
- Session 与 ServletContext 的区别
- URLEncoder 和 URLDecoder
- 五、JavaBean
- 六、MVC三层架构
- 七、Filter 接口 (重要)
- 抽象方法
- 案例:用户登录注销 拦截
- 八、监听器
- 八、文件传输
- 1、文件上传调优(注意事项)
- 2、文件上传 案例
- 九、邮件发送
- 1、单线程邮件发送
- 2、多线程邮件发送,注册
Java Web 02
servlet,cookie,session,filter,MVC,JavaBean
一、Servlet基本流程
1,创建一个类,继承HttpServlet
public class HelloServlet extends HttpServlet {
// 重写了doGet方法,该方法处理get请求
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException{
// 响应的类型
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
// 响应的输出流
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>你好!</h1>");
out.println("</body>");
out.println("</html>");
}
}
2,在web.xml,配置文件中注册servlet
<?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_3_1.xsd"
version="3.1"
metadata-complete="true">
<!--web.xml中是配置web的核心应用-->
<!--注册servlet-->
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.heroc.servlet.HelloServlet</servlet-class>
</servlet>
<!--一个servlet,对应一个mapping(映射)-->
<servlet-mapping>
<!--该映射名称要与servlet对应-->
<servlet-name>helloServlet</servlet-name>
<!--请求路径-->
<url-pattern>/h</url-pattern>
</servlet-mapping>
</web-app>
一个servlet对应一个servlet映射。
部署好tomcat之后,启动tomcat就可以通过localhost:8080/h
访问到HelloServlet类中get请求的处理。
流程:
前端浏览器,输入请求地址,然后定位到/h
,找到映射配置,<servlet-name>helloServlet</servlet-name>
找到,注册的servlet,就可以找到class,找到class,就可以在该calss中找到对应的请求方法。
为什么需要映射:
我们写的是java程序,浏览器只能访问web服务器,为了与java程序建立通信,就得在web服务器上,注册servlet,还需要给一个浏览器能够访问的路径。因此映射能够在服务器中建立起浏览器与java程序的连接。
二、Servlet
1、Servlet 接口
1)Servlet简介
Servlet是sun公司,开发动态web的一门技术。
Sun公司提供了Servlet接口,如果要开发一个servlet程序,步骤:
- 编写一个类,实现servlet接口
- 把开发好的程序部署到web服务器中
servlet是运行在web服务器中的小型java程序,通常通过HTTP协议接受和相应来自web客户端的请求。
Sun公司默认为Servlet写了两个实现类,分别是GenericServlet
、HttpServlet
2)Servlet原理
Servlet是由web服务器调用,web服务器收到浏览器请求之后,会
Servlet容器调用Servlet的过程。调用过程如下 首次访问该Servlet
1、调用init(ServletConfig config)
进行初始化,ServletConfig封装了web.xml中<init-param>
配置的初始化参数,它由Servlet容器创建,并通过该方法传递给当前serlvet
2、调用service(ServletRequest req, ServletResponse res)
方法处理客户的请求
3、调用destroy()
方法销毁给Servlet实例,当然这里只是为了说明完整流程,实际上destroy()
方法不是在调用servlet完成后就销毁。
抽象方法
public void init(ServletConfig config) throws ServletException;
该抽象方法的作用是:服务器启动时,就会初始化servlet。全程只会初始化一次public ServletConfig getServletConfig();
该抽象方法的作用是:该对象包含此 servlet 的初始化和启动参数public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
该抽象方法的作用是:由 servlet 容器调用,以允许 servlet 响应某个请求。public String getServletInfo();
该抽象方法的作用是:返回有关 servlet 的信息,比如作者、版本和版权public void destroy();
该抽象方法的作用是:销毁servlet,最后进行垃圾回收终止它。
2、GenericServlet 抽象类
GenericServlet抽象类,实现了Servlet
和ServletCofig
接口
两个init()方法重点
// 1,
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
// 2,
public void init() throws ServletException {
}
方法1,调用了方法2,但是方法2什么也没有做。事实上,GenericServlet类可以只写一个init方法,如果要对init方法进行特殊操作的话,就得继承GenericServlet重写init方法,往往在开发中,很容易将最关键的一句话this.config = config;
给漏掉,如果漏写,ServletConfig对象就是null,就无法使用ServletConfig对象。因此,为了避免该事情发生,保险起见,就写了两个init方法,一个固定的init方法,去初始化ServletConfig对象,然后调用另一个无参的init方法,我们只需要重写无参的init方法,对初始进行特殊操作,就可以了。
3、HttpServlet 抽象类
HttpServlet抽象类,继承了GenericServlet类
重写方法,不能使用super
继承HttpServlet重写方法时,不能加uper.doXXX(req, resp);
不然会报错,无法访问,返回4xx代码
比如doGet(req,resp)方法,如果不删除uper.doGet(req, resp); 访问该url,会调用HttpServlet的doGet方法,而这个doGet方法会返回405错误码 “http.method_get_not_supported” ,源码如下:
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
两个service()方法重点
// 1,
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
if (!(req instanceof HttpServletRequest &&
res instanceof HttpServletResponse)) {
throw new ServletException("non-HTTP request or response"); // 抛出异常
}
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
service(request, response);
}
该公共service方法由服务器自动调用,会将前端通过http协议,传递过来的请求,并判断是否是符合http协议,不是则抛出异常,是则进行强制性类型转换,调用本方法的另一个受保护的service方法。
其实该方法,有一个好处,如果出现了其他协议,也可以通过该方法,进行扩展。
因为,这里只是一个类型转换的一个方法,是服务器自动调用的。比如是一个http协议的请求和响应,那么就可以强制转换成HttpServletRequest和HttpServletResponse对象,然后调用对应的重载revice方法。如果出现了另一种协议,其实这里也可以将其转换成符合另一种协议的对象,然后再重载revice方法,进行调用即可。如果后期出现了另一种传输协议,java后期更易于去扩展该协议。
// 2,
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
该受保护的service方法,通过获取请求的请求方式,来调用对应的执行方法,如果是get请求,那么就调用doGet()方法。所以我们完全可以重写受保护的 service() 方法来代替 doPost() 和 doGet() 方法。
4、Mapping 映射路径
1)servlet与mapping映射路径的多个情况
- 一个servlet有一个映射路径
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.heroc.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
浏览器可通过/hello
找到HelloServlet类的doget处理方法
- 一个servlet有多个映射路径
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.heroc.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
浏览器可通过/hello
、/hello1
、/hello2
多个映射路径去访问一个servlet
- 一个servlet指定一个通用映射路径
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.heroc.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
浏览器可通过/hello/任意字符
都可以访问到HelloServlet处理后的结果
- 默认请求路径
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.heroc.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
如果直接映射路径使用/*
访问localhost:8080/
不会访问index.html默认的主页面,而是访问/*
对应注册的servlet内容。由此见,映射路径/*
优先级较高
- 指定后缀
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.heroc.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
浏览器访问的路径只有是.do
结尾的才可以访问到对应注册的servlet。注意,指定后缀*
符号前面不能加/
,否则会报错。
2)映射路径的优先级
<!--指定映射路径-->
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.heroc.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<!--通配符映射路径-->
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.heroc.servlet.Error</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
以上例子,虽然/hello
是属于/*
的范围中,但是通过浏览器访问/hello
,会跳转到/hello
注册的servlet,这里可以看出,固有的路径(指定的路径)优先级大于通配符的路径。
5、ServletContext 接口对象
javax.servlet Interface ServletContext
接口,就是servlet的容器,是web应用程序的上下文。SerletContext是全局唯一的,初始项目的时候就创建了该对象。
因此ServletContext接口可以实现多个Servlet之间的数据交流。定义一组方法,servlet 使用这些方法与其 servlet 容器进行通信。
常用方法
public Object getAttribute(String name);
返回具有给定名称的 servlet 容器属性,如果不具有该名称的属性,则返回null
。public void setAttribute(String name, Object object);
在servlet上下文中,给定一个键值对。如果servlet上下文中,已经存在某个属性,那么此方法将使用最新的属性值。public void removeAttribute(String name);
将servlet上下文中的,某个属性删除。public String getInitParameter(String name);
获得web.xml中配置的参数信息public RequestDispatcher getRequestDispatcher(String path);
请求转发(浏览器的路径不会发生变化)。可以通过该方法,转发到其他servlet中。public InputStream getResourceAsStream(String path);
读取资源文件,返回流对象
以下ServletContext的操作基本上不会使用,功能都会被其他类代替。
数据共享
public class HelloServlet01 extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException{
ServletContext context = this.getServletContext();
context.setAttribute("username","heroC"); // 向上下文中放入了一个节点
}
}
public class HelloServlet02 extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException{
ServletContext context = this.getServletContext(); // 获得全局唯一ServletContext对象
String name = (String)context.getAttribute("username"); // 从中获取指定节点
response.getWriter().write(name); // 向响应目的输出节点中的值
}
}
// 以上两个servlet就通过ServletContext对象实现了数据交互
获取参数
<!--web.xml-->
<context-param>
<param-name>urlname</param-name>
<param-value>jdbc:mysql://localhost:8080/db1</param-value>
</context-param>
<!--配置了一个名为urlname的参数信息-->
public class HelloServlet01 extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException{
ServletContext context = this.getServletContext();
String urlname = context.getInitParameter("urlname"); // 获取web.xml中的参数配置信息
}
}
请求转发
public class HelloServlet01 extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException{
ServletContext context = this.getServletContext();
context.getRequestDispatcher("/hello").forward(request, response);
// 通过浏览器访问到该servlet,该servlet处理中,会转发到“/hello”请求路径的servlet进行处理,将request, response都传递过去进行处理
}
}
读取资源文件
public class HelloServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException{
response.setCharacterEncoding("utf-8");
ServletContext context = this.getServletContext();
// 获取配置文件并将内容输入流
InputStream resource =
context.getResourceAsStream("/WEB-INF/classes/test.properties");
Properties prop = new Properties();
prop.load(resource); // 加载到properties集合类中
String username = prop.getProperty("username");
String password = prop.getProperty("password");
response.getWriter().print(username+":"+password);
}
}
<?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_3_1.xsd"
version="3.1"
metadata-complete="true">
<!--web.xml中是配置web的核心应用-->
<!--注册servlet-->
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.heroc.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
请求转发与重定向的区别 重点
resource为servlet中的任意操作
转发请求:
A需要访问resource,但是只能通过B去得到resource,B得到了resource,再将resource返回给A。转发请求的请求路径不会发生变化。
重定向:
A需要访问resource,但resource是B中的资源,A通过访问B,B告诉了A怎么去访问resource,A直接去访问resource。通过重定向,请求路径会发生变化。
相同点:
- 页面都会实现跳转
不同点:
- 转发不会改变请求的URL (ServletContext和HttpServletRequest都可以实现转发) ;状态码 307
- 重定向会改变请求的URL ; 状态码 302
- 转发可以给HttpServletRequest设置一个节点,可以传递参数;而重定向只能转发页面,不能传递参数
6、HttpServletRequest 接口
获取前端的参数
String userNname = request.getParameter("username");
String[] likes = request.getParameterValues("like");
// 第一个获取请求URL中username的值
// 第二个获取like中的多个值,可能like代表的是一个多选框,返回多个值
请求转发
除了ServletContext可以实现转发,HttpServletRequest也可实现转发
request.getRequestDispatcher("/code").forward(request,response);
7、HttpServletResponse 接口
在HttpServletResponse接口中定义了很多状态码。以及对请求做出响应的一些get/set方法,以及给浏览器发送信息的一些方法。
浏览器下载文件
resp.setHeader("Content-Disposition",
"attachment;filename="+URLEncoder.encode(fileName,"UTF-8"));
// 重点,给浏览器一个头信息,让浏览器执行下载文件
Download.java
public class Download extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 当我们重写doGet方法时,不能加入这句话,因为父类doGet方法会返回405错误码
// super.doGet(req, resp);
//ServletContext context = this.getServletContext();
// String realPath = context.getRealPath("/1000x.mp3"); // 获取不到资源
// System.out.println(realPath);
String realPath = "E:\idea-workspace\javaweb\src\main\resources\1000x.mp3";
String fileName = realPath.substring(realPath.lastIndexOf("\") + 1);
// 让浏览器下载文件的头信息
// Disposition处置 attachment附件
resp.setHeader("Content-Disposition",
"attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
InputStream in = new FileInputStream(realPath);
ServletOutputStream out = resp.getOutputStream();
int len = 0;
byte[] buffer = new byte[1024];
while ((len=in.read(buffer)) != -1){
out.write(buffer,0,len); // 向客户端写文件
}
in.close();
out.close();
}
}
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_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>download</servlet-name>
<servlet-class>com.heroc.download.Download</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>download</servlet-name>
<url-pattern>/downMusic</url-pattern>
</servlet-mapping>
</web-app>
验证码实现
验证码实现方式:
- 前端实现
- 后端实现,需要用到图片类,生产一个图片
public class SafeCode extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置浏览器刷新时间
resp.setHeader("refresh","5");
// 通过图片类,创建一个长为80,宽为20,使用BGR颜色格式
BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_3BYTE_BGR);
// 通过图片类,获取一个画笔
Graphics pen = image.getGraphics();
pen.setColor(Color.white); // 给画笔设置一个颜色
pen.fillRect(0,0,80,20); // 用画笔在图片(画布)上从坐标(0,0)开始填充整个图片
// 将生成的随机数,画到图片上
String randNum = randomNum();
pen.setColor(Color.blue);
pen.setFont(new Font("宋体",Font.BOLD,20));
pen.drawString(randNum,0,20);
// 告诉浏览器,格式为图片,并且此Servlet响应的数据关闭缓存
resp.setContentType("image/jpeg");
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Program","no-cache");
// 将图片通过图片流写出去
ServletOutputStream out = resp.getOutputStream();
ImageIO.write(image,"jpg",out);
out.close();
}
public static String randomNum(){
Random random = new Random();
String num = random.nextInt(9999999)+""; // 生成0~9999999的随机整数
StringBuffer buffer = new StringBuffer(num);
for (int i = 0; i < 7 - buffer.length() ; i++) {
// 如果生成的随机数不足以7位,就用0来补位
buffer.append(0);
}
return buffer.toString();
}
}
// 生成随机字母
Random random = new Random();
int num = 65 + random.nextInt(26); // [0,26)
System.out.print((char)num);
重定向 (重要)
public class RedirectTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
重定向实则实现了以下代码 /javaweb 是配置tomcat时,给的一个默认访问起始路径
resp.setHeader("Location","/javaweb/code");
resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); // 状态码302
*/
resp.sendRedirect("/javaweb/code");
}
}
三、Cookie 类
import javax.servlet.http.Cookie;
cookie中文为饼干
cookie的作用是用于辨别客户端的身份。cookie是存在客户端的。每个网站都有自己的cookie。
cookie就如同服务端给客户端的一个信件、标识,服务端可以通过这个来辨别客户端是否访问过该服务端。
客户端请求服务器,服务器可以通过请求对象获取客户端的cookie,从cookie中可以找到这个服务端给客户端的信件,如果没有给这个客户端设置过cookie或者找不到这个服务端为客户端设置的cookie,那么就给客户端新建一个cookie,以便于下次这个客户端访问这个服务器时的一个身份辨别。
cookie是由服务器给客户端的信息,由客户端(浏览器)存储。
public class CookieT extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
Cookie[] cookies = req.getCookies(); // 获取客户端的cookie
if(cookies!=null){
for (int i = 0; i < cookies.length; i++) {
if(cookies[i].getName().equals("heroC")){
// 如果有过这个服务端设置的cookie,就做一些业务操作
cookies[i].getValue(); // 获取cookie值
}
}
}else {
Cookie cookie = new Cookie("heroC", "该服务器给你的其中一条cookie");
cookie.setMaxAge(24*60*60); // 给cookie设置一个有效期,如果为0,那么有效期就为0秒
resp.addCookie(cookie); // 本服务端给客户端的一个cookie
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
各个浏览器的cookie大小、个数限制
四、Session 接口 (重点)
javax.servlet.http.HttpSession
接口
Session是“会话控制”,Session对象存储特定用户会话所需的属性及配置信息。
session中存储的信息是由服务器存储,发送给浏览器一个session的ID,一个session的ID对应存储在服务器的一个session对象。
session针对用户,一个用户一个session。
session由服务器创建。
作用:
- session可运用于购物车
public class SessionT 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,如果没有该用户的session就创建一个
HttpSession session = req.getSession();
// 给session设置键值对,值可以是一个对象,键为String类型
session.setAttribute("name","heroC");
if(session.isNew()){
resp.getWriter().write("创建了一个session "+session.getId());
}else {
resp.getWriter().write("已经存在一个session " + session.getId());
}
// session.invalidate(); // 将这个session,设置为过期
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<session-config>
<!--设置session的过期时间,单位为分钟-->
<session-timeout>1</session-timeout>
</session-config>
Cookie 与 Session 的区别与联系 重点
Cookies是属于Session对象的一种。但有不同,Cookies不会占服务器资源,是存在客服端内存或者一个cookie的文本文件中;而“Session”则会占用服务器资源。所以,尽量不要使用Session,而使用Cookies。但是我们一般认为cookie是不可靠的,session是可靠地,但是目前很多著名的站点也都以来cookie。有时候为了解决禁用cookie后的页面处理,通常采用url重写技术,调用session中大量有用的方法从session中获取数据后置入页面。
Session 与 ServletContext 的区别
- Session针对用户而言,一个用户有自己的Session的ID,而其他用户没有他session的ID,因此无法访问这个用户的session,只能访问自己的session。
- ServletContext是所有用户都可以访问的一个全局对象。可用于统计访问人数等。
URLEncoder 和 URLDecoder
import java.net.URLDecoder;
import java.net.URLEncoder;
// 解决乱码问题
URLEncoder.encode("str","utf-8"); // 将字符串,按照utf-8进行编译
URLDecoder.decode("str","utf-8"); // 将字符串,按照utf-8进行解析
五、JavaBean
JavaBean就是实体类,用于封装数据库中,查询到的数据记录的类
JavaBean特定写法:
- 必须有无参构造器
- 属性必须私有化
- 必须有对应的get和set方法
一般用于和数据库的字段做映射,ORM:对象关系映射
推荐放在以下命名的包中:
com.xxx.pojo
com.xxx.entity
com.xxx.vo
com.xxx.dto
六、MVC三层架构
MVC:model view controller 模型/视图/控制器
模型就如同javabean,与数据库字段一一对应的实体类
视图就如同前端页面
控制器就如同servlet
七、Filter 接口 (重要)
javax.servlet Interface Filter
过滤器接口,用于过滤网站的数据
抽象方法
public void init(FilterConfig filterConfig)
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
public void destroy()
实现Filter的步骤:
- 创建一个类并实现Filter接口
- 重写Filter接口中的抽象方法
- 在web.xml中配置过滤路径
MyFilter.java
public class MyFilter implements Filter {
// 过滤器初始化:服务器启动时初始化
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter初始化");
}
// 过滤器,指定路径进行过滤
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 由于在每一个servlet上都会设置编码,所以可以在过滤器里设置编码,减少冗余代码
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
// 固定写法,一定要通过chain调用doFilter,让请求继续往下走
chain.doFilter(request,response);
}
// 过滤器销毁:服务器关闭时销毁
@Override
public void destroy() {
System.out.println("MyFilter销毁");
}
}
ServletFilter.java
public class ServletFilter extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
out.write("你好,过滤器");
}
@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_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>helloFilter</servlet-name>
<servlet-class>com.heroc.filter.ServletFilter</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloFilter</servlet-name>
<url-pattern>/filter/show</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>helloFilter</servlet-name>
<!--走该路径不会过滤-->
<url-pattern>/show</url-pattern>
</servlet-mapping>
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.heroc.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<!--指定路径下的请求走过滤器进行过滤-->
<url-pattern>/filter/*</url-pattern>
</filter-mapping>
</web-app>
结果:
访问localhost:8080/filter/show
走过滤器,过滤器会进行编码,页面正常显示结果
访问localhost:8080/show
不走过滤器,页面显示乱码
案例:用户登录注销 拦截
<!--/login.html-->
<html>
<body>
<h1>登录</h1>
<form action="/login" method="post">
<input type="text" name="username">
<button type="submit">登录</button>
</form>
</body>
</html>
<!--/error.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>错误</title>
</head>
<body>
<h1>登录失败</h1>
<a href="/index.html">返回登录页面</a>
</body>
</html>
<!--/sys/ok.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>成功</title>
</head>
<body>
<h1>登录成功</h1>
<a href="/loginout">注销</a>
</body>
</html>
// 处理/login请求
public class Login extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
if(username.equals("admin")){
req.getSession().setAttribute("USER_SESSION",req.getSession().getId());
resp.sendRedirect("/sys/ok.html");
}else {
resp.sendRedirect("/error.html");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
// 处理/loginout请求
public class LoginOut extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object session = req.getSession().getAttribute("USER_SESSION");
if(session!=null){
req.getSession().removeAttribute("USER_SESSION");
resp.sendRedirect("/index.html");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
// 过滤器
public class LoginFilter 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("USER_SESSION") == null){
resp.sendRedirect("/error.html");
}
chain.doFilter(req,resp);
}
@Override
public void destroy() {}
}
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.heroc.login.Login</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>loginout</servlet-name>
<servlet-class>com.heroc.login.LoginOut</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginout</servlet-name>
<url-pattern>/loginout</url-pattern>
</servlet-mapping>
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.heroc.login.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/sys/*</url-pattern>
</filter-mapping>
八、监听器
javax.servlet.http Interface HttpSessionListener
http的session监听器
public class OnlineCountListener implements HttpSessionListener{
// 创建一个session监听
// 一但创建session就会触发一次该事件
@Override
public void sessionCreated(HttpSessionEvent se) {
// 获取全局servletContext对象
ServletContext context = se.getSession().getServletContext();
Integer onlineCount = (Integer) context.getAttribute("OnlineCount");
if(onlineCount==null){
// 如果为null,说明之前没有人在线,所以你登陆了该网站,就是第一个在线的人
onlineCount = new Integer(1);
}else {
// 如果不为null,就在值的位置增1
int count = onlineCount.intValue();
onlineCount = new Integer(count++);
}
context.setAttribute("OnlineCount",onlineCount);
}
// 销毁一个session监听
// 一但session会话结束,就会触发一次该事件
@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--);
}
context.setAttribute("OnlineCount",onlineCount);
}
}
八、文件传输
1、文件上传调优(注意事项)
- 为保证服务器安全,上传的文件应该放在无法访问的目录之下,比如放在WEB-INF文件之下
- 保证上传文件的名字唯一,不能重复,防止重名文件而被覆盖(可通过时间戳、UUID、MD5、位运算算法等)
- 要限制上传文件的大小
- 可以限制上传文件的类型,判断文件类型是否合法
2、文件上传 案例
fileupload.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Layui</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
</head>
<body>
<!--文件上传必须有enctype="multipart/form-data"属性-->
<form action="/upload" method="post" enctype="multipart/form-data">
<p>用户名:<input type="text" name="username"></p>
<p><input type="file" name="file"></p>
<p><button type="submit">上传</button> | <button type="reset">重新选择</button></p>
</form>
</body>
</html>
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_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>fileupload</servlet-name>
<servlet-class>com.heroc.fileupload.FileUpload</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>fileupload</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
</web-app>
pom.xml
<?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</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- commons-io 与 commons-fileupload 为文件上传的包-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
</project>
FileUpload.java
public class FileUpload extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(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();
}
// 创建一个临时保存路径,如果上传文件大于限定值,就存入临时保存路径
String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File tmpFile = new File(tmpPath);
if(!tmpFile.exists()){
tmpFile.mkdir();
}
// 1. 创建DiskFileItemFactory对象,用于处理文件的上传路径或大小限制
DiskFileItemFactory factory = new DiskFileItemFactory();
// 当文件大于1024*1024这个大小时,上传到临时保存路径中
factory.setSizeThreshold(1024*1024);
factory.setRepository(tmpFile);
// 2. 创建ServletFileUpload对象
ServletFileUpload upload = new ServletFileUpload(factory);
// 监听文件上传进度
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("总大小:"+pContentLength+" 已上传:"+pBytesRead);
}
});
// 处理乱码
upload.setHeaderEncoding("UTF-8");
// 设置单个文件的最大值 10M
upload.setFileSizeMax(1024*1024*10);
// 设置总共能上传文件的大小 10M
upload.setSizeMax(1024*1024*10);
// 3. 处理上传文件
try {
// 将表单中的每一项,封装为一个item
List<FileItem> fileItems = upload.parseRequest(req);
for (FileItem fileItem : fileItems) {
if(fileItem.isFormField()){ // 判断文件是普通表单还是带文件的表单
// 普通表单
String name = fileItem.getFieldName();
String value = fileItem.getString("UTF-8");
System.out.println(name + ": " + value);
}else {
//===========================处理文件===========================//
// 带文件表单,拿到文件名
String name = fileItem.getName();
// 不符合规范的文件名,则放弃
if(name.trim().equals("") || name==null){
continue;
}
// 获得文件名如同:/images/picture.png 需要获取picture.png的文件名
String fileName = name.substring(name.lastIndexOf("/") + 1);
// 拿到文件的扩展名
String fileExtName = name.substring(name.lastIndexOf(".") + 1);
System.out.println("文件名:"+fileName+" 扩展名:"+fileExtName);
// 使用UUID为了使得文件不重名,避免重名带来的文件覆盖问题
String uuid = UUID.randomUUID().toString();
//===========================存放地址===========================//
String realPath = uploadPath+"/"+ uuid;
File realFile = new File(realPath);
if(!realFile.exists()){
realFile.mkdir();
}
//===========================文件传输===========================//
// 获取该表单项的输入流
InputStream inputStream = fileItem.getInputStream();
// 创建一个输出流
FileOutputStream fileOutputStream = new FileOutputStream(realPath + "/" + fileName);
int len = 0;
byte[] bytes = new byte[1024];
while((len = inputStream.read(bytes)) != -1){
fileOutputStream.write(bytes,0,len);
}
fileOutputStream.close();
inputStream.close();
System.out.println("文件上传成功!");
resp.sendRedirect("/fileupload.html");
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
九、邮件发送
MIME 多用途互联网邮件扩展类型。通俗说就是附件、图片。
<!-- javax.mail 与 javax.activation 为发送邮件的包-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
1、单线程邮件发送
// 发送只有文字内容的简单邮件
public class MailT{
public static void main(String[] args) throws GeneralSecurityException, MessagingException {
Properties properties = new Properties();
// key值是写死了的
properties.setProperty("mail.host","smtp.qq.com"); // QQ邮件服务器
properties.setProperty("mail.transport.protocol","smtp"); // 发送邮件协议
properties.setProperty("mail.smtp.auth","true"); // 需要验证用户密码
// 关于QQ邮箱,需要设置SSL加密
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable","true");
properties.put("mail.smtp.ssl.socketFactory",sf);
// QQ邮箱才有这段代码创建定义整个应用程序所需的环境信息的Session对象javax.mail.Session;
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
// 发件人邮件用户名,授权码
return new PasswordAuthentication("herocheung@foxmail.com",
"shyamjhysyhmbbgc");
}
});
// 开启session的debug模式,这样就可以将日志信息在后台打印出来
session.setDebug(true);
// 通过session获取transport对象
Transport transport = session.getTransport();
// 使用邮箱的用户名和授权码连接上邮箱服务器
transport.connect("smtp.qq.com","herocheung@foxmail.com", "shyamjhysyhmbbgc");
// 创建邮箱 消息对象MimeMessage
MimeMessage message = new MimeMessage(session);
// 指明邮件发件人
message.setFrom(new InternetAddress("herocheung@foxmail.com"));
// 指明邮件的收件人,收件人可以是一个数组
message.setRecipient(Message.RecipientType.TO,
new InternetAddress("herocheung@foxmail.com"));
// 邮件标题
message.setSubject("只包含文本的简单邮件");
// 邮件的内容
message.setContent("你好啊!","text/html;charset=utf-8");
// 发送邮件 第一个参数发送的信息对象,第二参数获得收件人
transport.sendMessage(message,message.getAllRecipients());
transport.close();
}
}
MimeMultipart类 将各个模块封装起来的类型,各个类型向下兼容
MimeMultipart类 是一个封装类,邮件中文本、内嵌资源、附件都是一个一个的MimeBodyPart类,然后统一封装到一个类中,最后添加在message对象中,由transport类进行发送
// 发送有附件图片的邮件
public static void main(String[] args){
try {
Properties properties = new Properties();
properties.setProperty("mail.host","smtp.qq.com"); // QQ邮件服务器
properties.setProperty("mail.transport.protocol","smtp"); // 发送邮件协议
properties.setProperty("mail.smtp.auth","true"); // 需要验证用户密码
MailSSLSocketFactory factory = new MailSSLSocketFactory();
factory.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable","true");
properties.put("mail.smtp.ssl.socketFactory",factory);
Session session = Session.getDefaultInstance(properties,
new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("herocheung@foxmail.com",
"shyamjhysyhmbbgc");
}
});
session.setDebug(true);
Transport transport = session.getTransport();
transport.connect("smtp.qq.com","herocheung@foxmail.com",
"shyamjhysyhmbbgc");
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("herocheung@foxmail.com"));
message.setRecipient(Message.RecipientType.TO,
new InternetAddress("herocheung@foxmail.com"));
message.setSubject("这是通过servlet发送含有图片的邮件");
// ========================================================================
// 存储图片块
MimeBodyPart img = new MimeBodyPart();
// 将附件进行数据处理
DataHandler handler = new DataHandler(new FileDataSource(
"D:\照片\IMG_20191127_181018.jpg"));
img.setDataHandler(handler);
img.setContentID("img.jpg"); // 设置资源的cid,后面会用到
// 存储文本块
MimeBodyPart text = new MimeBodyPart();
// 在引入图片时,通过cid:img.jpg形式引入
text.setContent(
"这是一封含图片的邮件<img src='cid:img.jpg'>","text/html;charset=utf-8");
// 将每个块封装到一起
MimeMultipart mimeMultipart = new MimeMultipart();
mimeMultipart.addBodyPart(img);
mimeMultipart.addBodyPart(text);
mimeMultipart.setSubType("mixed"); // 设置一个封装等级
// ========================================================================
message.setContent(mimeMultipart); // 在message中添加该封装块
message.saveChanges(); // 保存
transport.sendMessage(message,message.getAllRecipients()); // 发送邮件
transport.close();
} catch (GeneralSecurityException | NoSuchProviderException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
}
2、多线程邮件发送,注册
合理使用多线程,可以增强用户体验感
User.java
该类用于存储注册用户信息
public class User implements Serializable {
private static final long serialVersionUID = 1130456772345234L;
private String username;
private String pwd;
private String email;
public User() {
}
public User(String username, String pwd, String email) {
this.username = username;
this.pwd = pwd;
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String name) {
this.username = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", pwd='" + pwd + '\'' +
", email='" + email + '\'' +
'}';
}
}
MailThread.java
该类为发送邮件的线程
public class MailThread implements Runnable {
private User user;
public MailThread() {
}
public MailThread(User user) {
this.user = user;
}
@Override
public void run() {
try {
Properties properties = new Properties();
properties.setProperty("mail.host", "smtp.qq.com"); // QQ邮件服务器
properties.setProperty("mail.transport.protocol", "smtp"); // 发送邮件协议
properties.setProperty("mail.smtp.auth", "true"); // 需要验证用户密码
MailSSLSocketFactory factory = new MailSSLSocketFactory();
factory.setTrustAllHosts(true);
properties.put("mail.smtp.ssl.enable", "true");
properties.put("mail.smtp.ssl.socketFactory", factory);
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("herocheung@foxmail.com", "shyamjhysyhmbbgc");
}
});
session.setDebug(true);
Transport transport = session.getTransport();
transport.connect("smtp.qq.com", "herocheung@foxmail.com", "shyamjhysyhmbbgc");
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("herocheung@foxmail.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));
message.setSubject("heroC网站注册 -- 请记住");
message.setContent("<h1>欢迎注册heroC网站</h1> <h3>您已注册成功!您在本站注册的用户名: "+user.getUsername()+", 密码:"+user.getPwd()+"</h3><h3>谢谢您的注册!</h3>", "text/html;charset=utf-8");
transport.sendMessage(message, message.getAllRecipients());
transport.close();
} catch (GeneralSecurityException | NoSuchProviderException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
MailThreadServlet.java
该类接收前端发送的请求,并开启发送邮箱线程,并向前端发送结果
public class MailThreadServlet extends HttpServlet {
@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 pwd = req.getParameter("pwd");
String email = req.getParameter("email");
User user = new User(username, pwd, email);
new Thread(new MailThread(user)).start();
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("已注册成功!<br> 邮件已发送,可能由于网络原因,有所延迟,请注意查收!");
}
}
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>heroC注册</title>
</head>
<body>
<form action="/register" method="post">
<p>用户名:<input type="text" name="username"></p>
<p>邮箱:<input type="text" name="email"></p>
<p>密码:<input type="password" name="pwd"></p>
<p><button type="submit">注册</button></p>
</form>
</body>
</html>
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_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>register</servlet-name>
<servlet-class>com.heroc.mail.mailthread.MailThreadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>register</servlet-name>
<url-pattern>/register</url-pattern>
</servlet-mapping>
</web-app>