Http

HTTP

  • 运行在TCP之上
  • 端口:80

Https

  • 安全的
  • 443

Http请求

请求行

  • 请求方式:Get,Post,HEAD,DELETE,PUT,TRACT..
  • get:请求能够携带的参数比较少,大小有限制,会在浏览器的URL地址栏显示数据内容,不安全,但高效
  • post:请求能够携带的参数没有限制,大小有限制,会在浏览器的URL地址栏显示数据内容,安全,但高效

请求头

Accept:		     告诉浏览器,它所支持的数据类型
Accept-Encoding: 支持哪种编码格式 GBK UTF-8 GB2312 Is08859-1
Accept-Language: 告诉浏览器,它的语言环境
Cache-Contro1: 缓存控制
Connection: 告诉浏览器,请求完成是断开还是保持连接

Http响应

响应体

Accept:			告诉浏览器,它所支持的数据类型
Accept-Encoding: 支持哪种编码格式 GBK UTF-8 GB2312 Is08859-1
Accept-Language: 告诉浏览器,它的语言环境
Cache-Control: 缓存控制
Connection: 告诉浏览器,请求完成是断开还是保持连接
HoST: 主机..../.
Refresh: 告诉客户端,多久刷新一次:
Location: 让网页重新定位;

响应状态码

  • 200:成功
  • 3**:请求重定向(跳转指定位置)
  • 4**:找不到资源 / 资源不存在 (404)
  • 5**:服务器代码错误 (500)(502:网关错误)

响应编码格式

resp.setContentType("text/html;charset=utf-8");





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>

设置首页

<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>

错误页

<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/404.jsp</location>
</error-page>

<!--默认(404)类似转发-->
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

servlet

<!--注册Servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.chen.servlet.HelloServlet</servlet-class>
</servlet>

<!--Servelt的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

session

<!--设置Session默认的失效时间-->
<session-config>
<!--x 分钟后Session自动失效,以分钟为单位-->
<session-timeout>15</session-timeout>
</session-config>

Filter

<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.chen.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<!--只要是 /servlet 的任何请求,都会经过过滤器-->
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>

Listener

<!--注册监听器-->
<listener>
<listener-class>com.chen.listener.OnlineCountListener</listener-class>
</listener>





依赖

<dependencies>
<!-- servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>

<!-- JSP依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</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>





Servlet

简介

  • 开发Servlet程序

    • 编写一个类实现Servle接口
    • 把开发好的Java类部署到web服务器中
  • 把实现了Servlet接口的Java程序叫做Servlet


原理

image-20230711130130019


HelloServlet

1.实现Servlet接口,这里直接继承HttpServlet

public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();//响应流

writer.println("HelloServlet");
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}


2.编写 Servlet 映射(web.xml)

  • ① 注册servlet
  • ② 映射路径

为什么需要映射:写的是AVA程序,但是要通过刘览器访问,而浏览器需要连接Wb服务器,所以需要再web服务中注册我们写的Servlet,还需给他一个浏览器能够访问的路径;

<!--注册Servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.chen.servlet.HelloServlet</servlet-class>
</servlet>

<!--Servelt的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

3.配置Tomcat


Mapping

1.一个Servle可以指定一个映射路径

<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

2.一个Servlet可以指定多个映射路径

<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hellohello</url-pattern>
</servlet-mapping>

3.一个Servleti可以指定通用映射路径

  • /hello/任意字符
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>

4.默认请求路径

  • / 后面可以任意字符
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

5.指定一些后缀或者前缀等等.…

  • .chen为后缀即可
<!--可以自定义后缀实现请求映射
注意点,*前面不能加顶目映射的路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>任意字符.chen</url-pattern>
</servlet-mapping>

6、指定错误界面

  • 404
  • 500
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/404.jsp</location>
</error-page>

<!--默认(404)类似转发-->
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>

优先级

  • 指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求

  • 小范围优先

<!--指定固有路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

<!--默认(404)-->
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>



ServletContext

web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用:

ServletContext context = this.getServletContext();

1、共享数据

  • 在这个Servlet中保存的数据,可以在另外一个servlet中拿到

image-20230711160449099


  • :setAttribute(键值对)
//将一个数据保存在了getServletContext中,键值对形式存储
context.setAttribute("username",name);

  • 取:getAttribute
String username = (String) context.getAttribute("username");

2、获取初始化参数

  • 可在web.xml配置初始化参数

    <!--配置一些web应用的初始化参数-->
    <context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306:参数</param-value>
    </context-param>

  • 获取:getInitParameter(参数名称)

String url = context.getInitParameter("url");

3、请求转发

  • 不是重定向,请求不跳转,只不过获取第三方资源为自己使用,当前url不变

  • getRequestDispatcher(“转发路径”)

  • forward(req,resp)

RequestDispatcher requestDispatcher = context.getRequestDispatcher("/getc");//转发的请求路径

requestDispatcher.forward(req,resp);//调用forward实现请求转发


//请求转发
req.getRequestDispatcher("success.jsp").forward(req,resp);

4、读取资源文件

  • 在java目录下新建properties

  • 在resources目录下新建properties

  • 发现:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath:

  • 运行后看target包下该资源文件的路径

  • db.properties

    • username=root
      password=123123
      

      - 读取:需要一个文件流

      ```java
      //target包下该资源文件的路径
      InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
      Properties properties = new Properties();
      properties.load(resourceAsStream);


      String username = properties.getProperty("username");
      String password = properties.getProperty("password");






HttpServletResponse

  • 响应数据

    web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse;

如果要获取客户端请求过来的参数:找HttpServletRequest

如果要给客户端响应一些信息:找HttpServletResponse


1、分类

负责向浏览器发送数据的方法

ServletOutputStream getOutputStream() throws IOException;

PrintWriter getWriter() throws IOException;

负责向浏览器发送响应头的方法

void setCharacterEncoding(String var1);

void setContentLength(int var1);

void setContentLengthLong(long var1);

void setDateHeader(String var1, long var2);

void addDateHeader(String var1, long var2);

void setHeader(String var1, String var2);

void addHeader(String var1, String var2);

void setIntHeader(String var1, int var2);

void addIntHeader(String var1, int var2);


响应状态码

int SC_OK = 200;

int SC_FOUND = 302;

int SC_NOT_FOUND = 404;

int SC_INTERNAL_SERVER_ERROR = 500;

int SC_BAD_GATEWAY = 502;

2、向浏览器输出消息

  • getWriter
    • print
    • write
public class test extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println(username+":"+password);
resp.getWriter().write(username+":"+password);
}
}

3、验证码功能

  • 前端实现

  • 后端实现:需要用到Java的图片类,生成一个图片

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    //如何让浏览器5s自动刷新一次
    resp.setHeader("refresh","5");

    //在内存中创建一个图片
    BufferedImage bufferedImage = new BufferedImage(80,20, BufferedImage.TYPE_INT_RGB);
    //得到图片
    Graphics2D graphics = (Graphics2D)bufferedImage.getGraphics();//笔
    //设置图片的背景颜色
    graphics.setColor(Color.WHITE);
    graphics.fillRect(0,0,80,20);
    //给图片写数据
    graphics.setColor(Color.blue);
    graphics.setFont(new Font(null,Font.BOLD,20));
    graphics.drawString(makeNum(),0,20);

    //告诉浏览器,这个请求用图片的形式打开
    resp.setContentType("image/jpeg");
    //网站存在缓存,不让浏览器缓存
    resp.setDateHeader("expires",-1);
    resp.setHeader("Cache-Control","no-cache");
    resp.setHeader("Pragma","no-cache");

    //把图片写给浏览器
    ImageIO.write(bufferedImage, "jpg",resp.getOutputStream());

    }

    //生成随机数
    private String makeNum(){
    Random random = new Random();
    String num = random.nextInt(9999999) + "";
    StringBuffer stringBuffer = new StringBuffer();
    for (int i = 0; i < 7-num.length(); i++) {
    //不足7为0填充
    stringBuffer.append("0");
    }
    String s = stringBuffer.toString() + num;
    return s;
    }

5、实现重定向

  • sendRedirect
/*
resp.setHeader("Location","/responsep_war/redtext");
resp.setStatus(302);
*/
resp.sendRedirect("/responsep_war/redtext");
  • 面试题:请你聊聊重定向和转发的区别?
    相同点
  • 页面都会实现跳转
    不同点
    • 请求转发的时候,url不会产生变化
    • 重定向时候,url地址栏会发生变化;





HttpServletRequest

HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息

1、请求转发

req.getRequestDispatcher("success.jsp").forward(req,resp);

2、获取前端传递数据【*】

  • 获取请求中的数据
  • 单个:getParameter(“前端命名name”)
req.getParameter("username");
  • 多个:getParameterValues(“前端命名name”)
//数组
String[] hobbys = req.getParameterValues("hobbys");
System.out.println(Arrays.toString(hobbys));





Session、Cookie

  • 保存会话的两种技术

Cookie

  • 客户端技术(响应、请求)

image-20230715010024931


请求获取与响应

1.从请求中拿到cookie信息

2.服务器响应给客户端cookie

//从客户端获取 Cookie
Cookie[] cookies = req.getCookies();//返回数组,说明Cookie可能存在多个

//遍历cookie
Cookie cookie = cookies[i];
//获取cookie的 key
cookie.getName().equals("匹配的name")
//获取cookie的 value
cookie.getValue()

//新建一个cookie
Cookie cookie = new Cookie("名称name", 值);
//设置cookie的有效期
cookie.setMaxAge(24*60*60);

//响应给客户端一个cookie
resp.addCookie(cookie);
  • 一个Cookie只能保存一个信息;

  • 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie;

  • Cookie大小有限制4kb;

  • 300个cookie浏览器上限


删除Cookie

  • 不设置有效期,关闭浏览器,自动失效:

  • 设置有效期时间为0

    cookie.setMaxAge(0);

编码解码

  • cookie中value的值为中文的时候需要编码和解码
  • 编码:URLEncoder.encode(“值”,”utf-8”));
  • 解码:
//编码
Cookie cookie = new Cookie("lastLoginTime", URLEncoder.encode("值","utf-8"));

//解码
(URLDecoder.decode(cookie.getValue(),"UTF-8")

Cookie和Session的区别

  • Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以保存多个)
  • Session:把用户的数据写到用户独占Session中,服务器端保存(保存重要的信息,减少服务器资源的浪费)
  • Session对象由服务创建;


Session【*】

  • 服务器技术,利用这个技术,可以保存用户的会话信息,我们可以信息或者数据放在Session中!

image-20230715010204113

使用场景:

  • 保存一个登录用户的信息;

  • 购物车信息;

  • 在整个网站中经常会使用的数据,我们将它保存在Session中;


获得session

//得到Session
HttpSession session = req.getSession();

存入数据

//给Session中存入东西
session.setAttribute("name","辰呀");

获取ID及判新

//获取Session的ID
String sessionId = session.getId();
//判断Session是不是新创建的
if (session.isNew()) {
resp.getWriter().write("sessiom创建成功:ID: "+sessionId);
}else{
resp.getWriter().write("session以及在服务器中存在了,ID:"+sessionId);
}

读取数据

//获取session中的键值对应的值
String name =(String) session.getAttribute("name");

清除数据

session.removeAttribute("name");

注销Session

session.invalidate();

会话自动过期

  • web.xml配置
<!--设置Session默认的失效时间-->
<session-config>
<!--x 分钟后Session自动失效,以分钟为单位-->
<session-timeout>15</session-timeout>
</session-config>





MVC三层架构

MVC:Model(模型)、 view(视图) 、Controller(控制器)

image-20230717005803898

Model

  • 业务处理:业务逻辑(Service)
  • 数据持久层:CRUD(Dao)

View

  • 展示数据
  • 提供链接发起Servlet请求(a,form,img.…)

Conroller(Servlet)

  • 接收用户的请求:(req:请求参数、Session信息.…)
  • 交给业务层处理对应的代码
  • 控制视图的跳转
登录-->接收用户的登录请求--->处理用户的请求(获取用户登录的参数,username,password)---->交给业务层处理登录业务(判断用户名密码是否正确:事务)--->Dao层查询用户名和密码是否正确-->数据库





过滤器【*】

Filter:过滤器,用来过滤网站的数据;

1、导包

import导包需要导的是 import javax.servlet.;


2、编写过滤器

  • 实现 Filter 接口,重写3个方法
public class CharacterEncodingFilter implements Filter {
//初始化:wb服务器启动,就以及初始化了,随时等待过滤对象出现!
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterEncodingFilter已经初始化");
}

/*
1.过滤中的所有代码,在过滤将定清次的附族都会换行
2,必须要让过滤器继续执行 filterChain.doFilter(request,response);
*/
@Override
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("setCharacterEncoding执行前...");
filterChain.doFilter(servletRequest,servletResponse);//让我们的请求继续走,把请求转发下去交接,如果不写,程序在这拦截停止
System.out.println("setCharacterEncoding执行后...");
}

//销毁:服务器关闭的时候会被销毁
public void destroy() {
System.out.println("CharacterEncodingFilter已经销毁");
}
}

3、注册Filer

  • 和注册servlet类似
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.chen.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<!--只要是 /servlet 的任何请求,都会经过过滤器-->
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>

登录检测

用户登录之后才能进入主页!用户注销后就不能进入主页了!

1、用户登录之后,向Sesison中放入用户的数据

public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取前端请求的参数
String username = req.getParameter("username");
if (username.equals("admin")){
HttpSession session = req.getSession();
session.setAttribute("USER_SESSION",req.getSession().getId());
resp.sendRedirect("/Filer_01_war_exploded/sys/success.jsp");
}else {
resp.sendRedirect("/Filer_01_war_exploded/error.jsp");
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

2、进入主页的时候要判断用户是否已经登录:【过滤器实现

public class SysFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

//servletRequest httpRequest
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;

if (req.getSession().getAttribute("USER_SESSION")==null){
resp.sendRedirect("/Filer_01_war_exploded/error.jsp");
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {}
}

3、注册过滤位置

<filter>
<filter-name>SysFilter</filter-name>
<filter-class>com.chen.filter.SysFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SysFilter</filter-name>
<!--过滤访问/sys文件夹下的文件-->
<url-pattern>/sys/*</url-pattern>
</filter-mapping>





监听器

1、实现要监听对象的接口

  • 实例监听session(在线人数)
//统计网站在线人数:统计session
public class OnlineCountListener implements HttpSessionListener {

//创建session监听:看你的一举一动
//一旦创建Session.就会触发一次这个事件,
@Override
public void sessionCreated(HttpSessionEvent se) {
ServletContext servletContext = se.getSession().getServletContext();
System.out.println(se.getSession().getId());
Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount");
if (onlineCount==null) {
onlineCount=new Integer(2);
}
else {
int count = onlineCount.intValue();
onlineCount=new Integer(count+1);
}
servletContext.setAttribute("onlineCount",onlineCount);
}

//销毁session监所
//一且销毁然ession就会触发一次这个事件!
@Override
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext servletContext = se.getSession().getServletContext();
//销毁
se.getSession().invalidate();
Integer onlineCount = (Integer) servletContext.getAttribute("OnlineCount");
if (onlineCount==null) {
onlineCount=new Integer(1);
}
else {
int count = onlineCount.intValue();
onlineCount=new Integer(count-1);
}
servletContext.setAttribute("onlineCount",onlineCount);
}
}

2、注册监听器

<!--注册监听器-->
<listener>
<listener-class>com.chen.listener.OnlineCountListener</listener-class>
</listener>

3、JSP

<h1>当前有<span><%=this.getServletConfig().getServletContext().getAttribute("onlineCount")%>在线</span></h1>

GUI中的常见用法

public class TestPanel {
public static void main(String[]args){
Frame frame=new Frame("中秋节快乐");//新建一个窗体
Panel panel=new Panel(null);//面板
frame.setLayout(null);//设置窗体的布局
frame.setBounds(300,300,300,500);
frame.setBackground(new Color(6,0,255));//设置背景颤色
panel.setBounds(50,50,300,300);
panel.setBackground(new Color(6,255,0));//设置背景颤色
frame.add(panel);
frame.setVisible(true);

//监听事件,监听关闭事件
frame.addWindowListener(new WindowListener() {
public void windowOpened(WindowEvent e) {
System.out.println("打开");
}

public void windowClosing(WindowEvent e) {
System.out.println("关闭ing");
System.exit(0);
}

public void windowClosed(WindowEvent e) {
System.out.println("关闭ed");
}

public void windowIconified(WindowEvent e) {

}

public void windowDeiconified(WindowEvent e) {
}

public void windowActivated(WindowEvent e) {
System.out.println("激活");
}

public void windowDeactivated(WindowEvent e) {
System.out.println("未激活");
}
});
}
}






SMBMS案例

SMBMS项目






文件传输

1、提供下载

  • 在servlet中实现

1.要获取下载文件的路径

//1.要获取下载文件的路径
String realPath = "D:\\1.JavaRoute\\JavaWeb\\JavaWeb\\responsep\\target\\classes\\JavaWeb.md";

2.下载的文件名是啥?

//2( "/JavaWeb.md"   -----  获取最后一个"/"后面的字符串,所以+1)
String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);

3.设置想办法让浏览器能够支持下载我们需要的东西

//3.中文文件名URLEncoder.encode编码,否则有可能乱码
resp.setHeader("Content-disposition","attachment;filename="+ URLEncoder.encode(filename,"UTF-8"));


4.获取下载文件的输入流

FileInputStream fileInputStream = new FileInputStream(realPath);

5.创建缓冲区

int len= 0 ;
byte[] buffer = new byte[1024];

6.获取OutputStream对象

ServletOutputStream outputStream = resp.getOutputStream();

7.将FileOutputStream流写入到ouffer缓冲区,使用OutputStream将缓冲区中的数据输出到客户端!

while (fileInputStream.read(buffer)>0){
outputStream.write(buffer,0,len);
}

fileInputStream.close();
outputStream.close();
}

2、文件上传

依赖

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>

前端

  • 表单需要增加属性 enctype=”multipart/form-data”
<form action="  " enctype="multipart/form-data"	method="post">

<input type="file" name="file1">

<p><input type="submit"> || <input type="reset"></p>

</form>

后端代码编写

ServletFileUpload类

ServletFileUpload负责处理上传的文件数据,并将表单中每个输入项封装成一个Fileltem对象中.使用其parseRequest(HttpServletRequest)方法可以将通过表单中每一个HTML标签提交的数据封装成一个Fileltem对象,然后以List列表的形式返回。使用该方法处理上传文件简单易用。


public class FileServlet extends HttpServlet {
//处理表单
@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();//创建这个目录
}

/*
缓存:临时文件 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.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 {

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;

}
}






邮件发送

image-20230721180927506


依赖

<dependencies>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
</dependencies>

1、简单文本邮件

  • 邮件验证码(开线程实现)

  • //用户注册成功之后,给用户发送一封娜件
    //我们使用线程米专门发送娜件,防止出现耗时,和网站注册人数过多的情况:
    Sendmail send new Sendmail(user);
    //启动线程,线程启动之后就会执行run方法来发送娜件
    send.start();

public class MailTest01 {
public static void main(String[] args) throws MessagingException, GeneralSecurityException {
Properties prop = new Properties();
prop.setProperty("mai1.host","smtp.qq.com");//设置e邮件服务器
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);

//使用avaMaiL发送娜件的5个步骤
//1、创建定义整个应用程序所需的环境信息的Session对象
//QQ才有!其他邮箱就不用
Session session = Session.getDefaultInstance(prop,new Authenticator(){
public PasswordAuthentication getpasswordAuthentication() {
//发件人邮件用户名、授权码
return new PasswordAuthentication("1107383160@qq.com", "授权码");
}
});

//2、通过session得到transport.对象
Transport ts = session.getTransport();

//3、使用邮箱的用户名和授权码连上邮件服务器
ts.connect("smtp.qq.com","1107383160@qq.com","授权码");

//4、创建邮件
//传递sesson
MimeMessage message = new MimeMessage(session);

//指明邮件的发件人
message.setFrom(new InternetAddress("1107383160@qq.com"));

//指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发
message.setRecipient(Message.RecipientType.TO,new InternetAddress("2931303919@qq.com"));

//邮件的标题
message.setSubject("黄芪,text");

//==============================================================================================

//简单文本邮件
message.setContent("你好啊!","text/html;charset=UTF-8");

//==============================================================================================

//5、发送邮件
ts.sendMessage(message,message.getAllRecipients());

//6、关闭连接
ts.close();

}
}

2、带图片邮件

//==============================================================================================
//图片附件邮件

//准备图片数据
MimeBodyPart image = new MimeBodyPart();
//图片需要经过数据处理.·DataHandLer:数据处理
DataHandler dh = new DataHandler(new FileDataSource("D:\\1.JavaRoute\\JavaWeb\\JavaWeb\\Email\\web\\img\\ikun.png"));
image.setDataHandler(dh);//我们的Body中放入这个处理的图片数据
image.setContentID("bz.jpg");//给图片设置一个D,我们在后面可以使用!(cid)

//准备正文数据
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();//保存修政!
//==============================================================================================