JavaWeb-cnblog

tanzhenfei / 2023-08-29 / 原文

javaweb基础

HTML和CSS

<font color="" size="" face=""></font>

<br>//换行 <hr>

    //无序
      //有序

      //超链接

      //Javaweb相对路径

      //表格//行//列
      1.11.2..

      tr 行标签 th表头标签 td单元格标签 b加粗 cellspacing单元格间距

      colspan=“ #” 表跨#列合并 rowspan="#"表跨#行合并

      iframe的作用以及使用

      <iframe src="" name="abc"></if...>在页面开辟一个小区域,单独显示一个页面

      <a href=“” target=“abc">//target使用iframe

      表单

      image-20210731223323976

      image-20210731223353581

      表单格式化

      image-20210731223958712

      表单提交细节:

      action="":提交服务器地址 method="":get/post设置提交方式

      表提交的时候,数据没有发送给服务器的原因:

      1.表单项没有name属性

      2.单选,复选(下拉列表中option)都需要添加value属性

      3.表单不在提交的form标签中

      GET请求特点:

      1.浏览器地址栏中的地址是:action属性+?+请求参数(name+value&name+valu)

      2.不安全,有数据长度的限制

      POST特点:

      1.浏览器地址栏中的地址是:只有action属性

      2.安全,没有数据长度限制

      CSS其他标签

      div:默认独占一行

      span:长度是封装数据的长度

      p标签:段落标签

      JS

      声明函数

      函数声明1:function 函数名(可以带参,也可以不带){ 函数体 }

      函数声明2:var 函数名=function(形参列表){函数体}

      注意:js函数不允许重载,否则原先函数将会被覆盖

      object自定义对象

      • var 变量名=new Objject();

      • var 变量名={

      属性名:值,

      属性名:值,

      函数名:function(){}

      };

      事件

      image-20210801154950522

      点击事件(onclick)

      静态注册:

      Onload="被调用的函数"//浏览器解析完页面之后就会自动触发的事件

      动态注册:

      <button id="b1">按钮2</button>

      window.onload=function(){

      var btnobj =document.getElementById("b1")

      btnobj.onclick=function(){函数体}

      }

      失去焦点事件(onblur)

      静态注册

      function onblurFun(){

      console.log("静态注册失去焦点事件")//console是控制平台对象,向浏览器的控制台打印输出,用于测试。.log用于打印输出

      }

      动态注册

      window.onload=function(){

      var passworldobj=doucment.getElementById(" ");

      passworldobj.onblur=function(){函数体}

      }

      内容发生改变事件(onchang)

      静态

      <select onchange="f1">
      <option>..</option>
      </selec>

      动态

      <select id="f1">
      <option>..</option>
      </selec>

      动态:与前面相似

      DOM模型

      image-20210801230729660

      image-20210801231013082

      正则表达式

      • var patt=new RegExp(pattern,modifiers)

      • var patt=/pattern/modifiers/

      image-20210801235416413

      image-20210801235749127

      image-20210801235904258

      document对象查询优先顺序:id>name>tagname

      节点(标签对象)常用属性和方法:

      image-20210802001859522

      .基本概念

      web开发:

      静态web

      • HTML,css
      • 提供给所有人看的数据始终不会变化

      动态web

      • 淘宝,几乎所有网站

      • 提供给所有人的数据都会发生变化,不同时间不同地点看到的数据也不同

      • 技术栈:serviet/isp,asp,php

      2.1静态web

      *.html, *.htm这些都是网页后缀,如果服务器上存在这些东西,我们可以直接读取

      image-20210729145120693

      缺点:无法动态更新,无法和数据库交互

      2.2动态web

      image-20210729145855036

      缺点:如果服务器动态web资源出现了错误,我们需要重新编写我们的后台程序

      优点:可以动态更新,与数据库交互(数据持久化)

      image-20210729150313047

      .web服务器

      ASP:

      • 微软:国内最早流行的就是ASP
      • 在HTML中嵌入了VB脚本,ASP+COM

      php:

      优点:开发速度快,功能强大,跨平台,代码简单

      局限性:无法承载大访问量的情况

      JAP/Serviet:

      B/S:浏览和服务器

      C/S:客户端和服务器

      Jquery

      引入jquery库:

      jquery核心函数$

      $()就是调用$这个函数

      1.当传入参数是一个函数时,即【函数】,表示页面加载完成之后自动调用该函数,相当于window.onload=function(){}

      2.当传入参数是一个html字符串时,会根据这个字符串创建元素节点对象

      eg:$("

      "+"<span>div-span1</span>"+"
      ".appendTo("body"));

      3.当传入参数为【选择器字符串时】,表示根据id/标签名/类选择权查询标签对象

      eg:$("#id属性值");//id选择器 , $(“标签名”);//标签名选择器

      $(".class属性值");类选择器

      jquery对象:

      jquery对象是dom对象数组+jquery提供的一系列功能函数

      jquery对象与dom对象区别

      jquery对象不能使用dom对象的属性和方法,dom对象也不能使用jquery对象的属性和方法

      jquery对象是dom对象互转

      dom对象转为jquery对象:$(dom对象)

      jquery对象转为dom对象:jquery对象【下标】取出相应的dom对象

      image-20210802165744097

      基础选择器

      $("#id名"),$("*")//所有, $(".class名"), $("div,span")

      层级选择器

      $("form input")//找出表单所有input元素

      $("form >input")//找出表单所有的子集input元素

      $("label+input")//匹配所有跟在label后面的input元素

      $("form~input")//找到所有与表单同辈的input元素

      基本过滤选择器

      $("li(标签元素,可变):first/last");//获取匹配的第一个/最后一个元素

    1. .....

$("··:not(select)")//去除所有给定..选择器匹配的元素 :not(select)

$("tr:even")//查找表格中所有偶数行(tr) :even

$("tr:eq(2)")//查找第二行 :eq(index)

$("tr:gt(0)")//查找下标比0大的行,即从第二行查找 :gt(index)

$("tr:lt(2)")//查找下标比2小的行,即从第一行查找 到第二行 :lt(index)

$("h1:header")//查找h1标签 $(":header")

$(":animated")//匹配所有正在执行动画的元素

内容过滤器

$(":contains(text)")//找出某个元素下包含的文本元素

$(":empty")//匹配所有不包含子元素或者文本的空元素

$(":parent")//匹配所有包含子元素或者文本的空元素

$("div:has(p)")//匹配包含p元素的div元素 $(":has(selector)")

属性过滤器

$("div[id]")//查找含有id属性的div属性

$("input[name="dsm"]")//查找name为dsm的input属性

$("input[name^="dsm"]")//查找name以dsm开始的的input属性

$("input[name$="dsm"]")//查找name以dsm结束的的input属性

....

表单选择器

xml

作用:

1用来保存拥有自我描述性数据

2.可以作为项目或者模块的配置文件

3.可以作为网络传输数据的格式(现在以json为主)

构造一个xml文件

<?xml version="1.0" encoding="utf-8" ?>

eg:

平凡世界

...

.....

xml元素

image-20210802213522430

xml命名:名称可以含字母,数字以及其他字符,不能以数字,xml或者标点符号开始,不能包含空格

文本区域:

.Tomcat

初始Tomcat:

下载,启动,配置环境

image-20210729210505588

例题:网站如何进行访问的

输入域名,先检查本机的c:\windows\system32\drivers\etc\hosts配置文件下有没有这个域名映射

1.有:直接返回对应的ip地址,这个地址中,有我们需要访问的web程序,可以直接访问

2.没有:去DNS服务器找,找到的话就返回,找不到就返回找不到

image-20210729222408201

发布一个web网站

将自己写的网站放到服务器(Tomcat中)指定的web应用文件夹(webapps)下,就可以直接访问了

网站该有的结构

image-20210729231417651

自己尝试用tomcat发布一个静态网站:

image-20210730000946399

第二种部署web:

找到目录:conf\catalina\localhost下,创建一个.xml文件,写入如下内容:

//path:工程访问路径 docBase:工程目录地址

手托浏览器和手动输入地址访问浏览器区别:

手托浏览器:使用的协议是file://协议,浏览器直接读取file后面路径

手动输入地址访问浏览器:使用http协议

ROOT,index.html工程的默认访问

在浏览器地址栏中输入访问地址(http://ip:port),默认访问ROOT工程

在浏览器地址栏中输入访问地址(http://ip:port/工程名),默认访问index.html页面

servlet

servlet是运行在服务器上一个java小程序,是javaee规范(接口)之一,是javaweb三大组件(servlet程序,filter过滤器,listener监听器)之一。它可以接受客户端发送的请求,并且作出响应给客户端。

手动实现一个servlet工程

1.写一个类实现servlet接口

image-20211101185149339

2.重写servlet中所有方法,其中实现servic方法,此方法是接受请求并作出响应的

3.配置web.xml中servlet程序

image-20211101185212187

mapping路径的优先级问题:

指定了固有的映射路径优先级高,没有此固有映射路径则选择其他路由如通配符的映射路径“/*''

************使用注解代替xml的servlet配置(经常用,很方便)

image-20211101201521652

image-20211101201653204

URL解析

image-20210804145131619

Servlet周期

1.执行Serviet构造器方法

2.执行init初始方法

(仅在第一次访问的时候,第一,二步执行)

3.执行servic方法

(第三步每次访问都会被执行)

4.执行destroy销毁方法

(在web工程停止的时候,第四步才会停止)

servlet请求的分发处理image-20220709184349362

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
    System.out.println("3");
    HttpServletRequest httpServletRequest=(HttpServletRequest) servletRequest;
    //获取请求的方式
    String method= httpServletRequest.getMethod();
    if("GET".equals(method)){
        doget();
    }
    else{
        dopost();
    }
}
public void doget(){
    System.out.println("使用了get方法");
    System.out.println("使用了get方法");
    System.out.println("使用了get方法");
}
public void dopost(){
    System.out.println("使用了post方法");
    System.out.println("使用了post方法");
    System.out.println("使用了post方法");
}

通过继承httpservlet实现servlet程序

(实际开发中,都是使用此方法来实现servlet程序)

1.写一个类继承Httpservlet类

2.根据业务需要重写doget或者dopost方法

3.到web.xml中的配置servlet 程序的访问地址

image-20211101205249592

可以为一个dervlet设置多个url路径(2021版本的idea不加/):

image-20211101205730389

GenericServlet

servlet程序创建时如果继承servlet类则必须实现init,service,destory等方法,较为笨拙。即如果仅继承servlet的子类GenericServlet,则不必实现servlet全部解口,较为方便,但依然不经常使用,后面会学习HttpServlet类是较为常用的

image-20211101203719404

servlet继承体系

image-20210804172100129

image-20211101204501703

doget()和dopost封装了请求方式的获取

servletConfig类

作用:

1.获取servlet程序的别名servlet-name

servletConfig.getServletName();

2.获取初始化参数init-param

servletConfig.getInitParameter(name)//获取xml的初始化参数init-param,需要配置xml

image-20210804182210742

image-20210804190123235

3.获取servietContaxt对象

servletConfig.getservietContaxt();

ServletContext类

1.servletcontext是一个接口,表示servlet上下文对象

2.一个web工程,只有一个.servletcontext对象实例

3..servletcontext对象是一个域对象(像map一样可以存取数据的对象)

4.servletContext在web工程部署启动的时候的时候创建,在web工程停止的时候销毁

image-20210804183146631

四个作用:

1.获取web.xml中配置的上下文参数表context-param

image-20210804190528984

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ServletContext servletContext=getServletConfig().getServletContext();
    servletContext.getInitParameter("")
}
  • init-param只能由 servletconfig获取(servletconfig.getinit-param()😉

  • context-param只能由servletcontext对象获取

​ ServletContext c=getServletConfig().getServletContext();

​ c.getInitParameter("")

2.获取当前工程路径,格式:/工程路径

ServletContext c=getServletConfig().getServletContext();

c.getConttextPath();

3.获取工程部署后在服务器上的绝对路径

ServletContext c=getServletConfig().getServletContext();

c.getRealPath("/");//"/"表示http://ip:port/工程名/

eg:工程下css目录的绝对路径:...c.getRealPath("/css")

4.像map一样存数据

ServletContext c=getServletContext();//直接调用getServletContext();

c.setAttribute(key,value);//保存数据

c.getAttribute(key);

5.获取文件资源

image-20220709235305764

seervlet请求的http协议格式

get请求

image-20210804214833027

1.请求行

(1)请求方式 GET

(2)请求资源路径[+?+请求参数]

(3)请求的协议的版本号 HTTP/1.1

2.请求头

​ key :value组成,不同键值对表示不同含义

post请求

1.请求行

(1)请求方式 POST

(2)请求资源路径[+?+请求参数]

(3)请求的协议的版本号 HTTP/1.1

2.请求头

​ key :value组成,不同键值对表示不同含义

---------------空行----------------

3.请求体------>发送给服务器的数据

image-20210804215752965

区分GET请求和POST请求

1.get请求
  1. form标签 method=get
  2. a标签
  3. link标签引入css
  4. script标签引入js
  5. img标签引入图片
  6. iframe引入html页面
  7. 在浏览器中输入地址后敲回车
2.post请求

form标签 method=post

响应的HTTP格式

1.响应行

(1)响应的协议和版本号

(2)响应状态码

(3)响应状态描述符

2.响应头

key :value组成,不同响应,表示不同含义

————空行————

3.响应体——>>回传给客户的数据

image-20210804221311248

常用响应码:

image-20210804221428257

HttpServletRequest类

image-20210804222703877

HttpServletRequest类的常用方法

image-20210804222934926

设置请求体的字符集为UTF-8解决请求中午乱码问题(在获取请求参数之前调用)

red.setCharacterEncoding("UTF-8");

请求转发

请求是指,一个服务器收到请求后,从一个服务器资源跳到另一个服务器资源的操作

req.getRequestDispatcher("路径地址").forward(req,resq);

image-20210804232059136

servlet1:

image-20210804233141524

servlet2:

image-20210804233804706

特点:

image-20210804233007778

baseb标签

作用:base标签可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转

image-20210805000801319

(最后的c.html可以省略)

HttpServletResponse类

此类与HttpServletrequest类相似,每次请求进来,tomcat服务器都会创建一个Response对象传递给Servlet程序使用。HttpServletrequest表示请求过来的信息,HttpServletResponse表示所有响应的信息。

我们如果需要设置返回给客户的信息,可以通过HttpServletResponse对象进行回应

两个输出流响应信息给客户端

1.字节流

getoutputStream();//常用于下载(传递二进制数据)

2.字符流

getWriter();常用于回传字符串(常用)

俩流不能同时使用

Response中文乱码问题

resp.setCharacterEncoding("UTF-8");

resp.setHeader("Content-Type","text/html;charset=UTF-8");

请求重新定向

image-20210805004927786

image-20210805005100834

xml:

image-20210805005447501

response1:

image-20210805005259597

response2:

image-20210805005655094

image-20210805005855110

设置response第二种方法

image-20210805010050103

response文件下载:

//获取下载路径
        String path=" ..../1.pang";
//        获取下载文件名称
        String name=path.substring(path.lastIndexOf("//"+1));
//        设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西
        resp.setHeader("Content-Disposition","attachment;filename="+name);
//        获取下载输入流
        FileInputStream in = new FileInputStream(path);
//        创建缓冲区
        int len=0;
        byte[] buffer = new byte[1024];
//        获取输出流对象
        ServletOutputStream out = resp.getOutputStream();
//        将fileoutputstream流写入buff缓冲区,使用outputstream将缓冲区的数据传出给客户端
        while ((len=in.read(buffer))>0){
            out.write(buffer,0,len);
        }
        
        in.close();
        out.close();

JSP(java server pages)

jsp即服务器页面,主要作用是用来代替servlet程序回传html页面的数据

由于servlet程序回传html 页面数据繁琐,开发和维护成本高

1.jsp本质

就是一个servlet程序

image-20220718105602933

当我们第一次访问jsp页面时,tomcat服务器会帮我们把jsp页面翻译成一个java源文件,并且对它进行编译成为.class字节码程序。jsp翻译出来的java类间接继承了Httpservlet,即翻译出来的是一个servlet类。

底层代码也是通过输出流,把html回传给客户端

image-20210805091725947

2.page指令

1.language属性 表示翻译后是什么语言文件,暂时只支持java

2.contentTyp属性 表示jsp返回的数据类型是什么,源码中response.contenttype()参数值

3.pageEncoding属性 表示当前jsp文件本身的字符集

4.import属性 导包,导类

————以下是给out输出流使用————

3.autoFlush属性 设置当out输出流缓冲区满了之后,是否自动刷新缓冲区,默认值是true

4.buffer属性 设置out缓冲区的大小,默认是8kb

————————

5.errorPage属性 设置jsp运行出错时,自动跳转的页面路径

6.isErorPage属性 设置当前jsp页面是否是错误的信息页面,默认是fale

7.session属性 设置访问当前jsp页面是否会创建HttpSession对象,默认是true

8.extends属性 设置jsp翻译出来的java类默认继承

eg:<%@ page language=" ..." contentType="..." pageEncoging="..."%>

3.jsp脚本

声明脚本(很少用)

格式:<%! 声明脚本%>

作用:

声明类的属性:

<%!

privat Integer id;

privat String name;

private static Map;

%>

声明static 静态代码块

<%!

static{

map= new HashMap<String,Object>;

map.put("key","value");

}

%>

声明类的方法

<%!

public int abc(){}

%>

声明内部类

<%!

public class abc{

privat Integer id=12;

privat String name;

}

%>

表达脚本(常用)

表达式:<%= 表达式 %>

作用:在jsp页面上输出数据(整型,浮点型,字符串,对象)

eg:<%=12%>...<%=12.12%>...<%="我是字符串"%>...<%=map%>

特点:

1.所有表达式脚本都会被翻译到_jspservice方法中

2.表达式脚本都会被翻译成为out.print()输出到页面上

3.由于所有表达式脚本都会被翻译到__jspservice方法中,所以_jspservice方法对象可以直接使用

4.表达式脚本中的表达式不能用分号“;”结束

代码脚本

格式:<% 代码 %>

作用:在jsp文件中编写我们自己所需要的功能

代码脚本特点:

1.代码脚本翻译之后都在_jspservic方法中

2.代码脚本都会被翻译到__jspservice方法中,所以_jspservice方法对象可以直接使用

3.可以由多个代码脚本完成一个完整的Java语句

image-20210805120342374

4.代码脚本还可以和表达式脚本一起组合使用,在jsp页面完成数据输出

image-20210805120034707

4.jsp三种注释

1.html注释

2.Java注释

//单行注释

/* 多行注释 */

3.jsp注释

<%--多行注释--%>

可以注释掉jsp页面所有代码

注意:

jsp注释不会显示在客户端,html注释会显示

5.jsp九大内置对象

jar包源码展示

final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;

image-20210805125706381

6.四大域对象

image-20210805182437261

四个域都可以像map一样存数据,不同的是他们对数据的存取范围

使用的优先顺序为从小到大,即:pagContext-->request-->session-->application

7.out和response区别

jar包源码展示:


  response.setContentType("text/html;charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);               //page
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();  //application
      config = pageContext.getServletConfig();
      session = pageContext.getSession();         //session
      out = pageContext.getOut();
      _jspx_out = out;

总是先输出response,再输出out内容,原因如下:

当jsp页面中所有代码执行完成之后会做以下两个操作:

1.执行out.flush()操作 ,会把out缓冲区的数据写入到response缓冲区末尾

2.执行response的刷新操作,即把全部数据写给客户端

image-20210805211026336

由于jsp翻译之后,底层源代码都是使用out进行输出,所以一般情况下,我们都是统一在jsp页面中使用out输出,避免打乱页面输出顺序

注意out.write 与out.print()区别

out.write()输出字符串没问题(其他数据例如整型数据等输出就会有问题,关于ASCLL转换问题)

out.print()输出任何数据都没有问题(都转换成字符串后调用write输出)

8.jsp常用标签

静态包含

<%@ include file="你要包含的jsp页面路径"%>

特点:

静态包含不会翻译被包含的jsp页面

静态包含其实是把包含的jsp页面代码拷贝到包含的位置执行输出,将两个页面合二为一,本质是一个页面上的

动态包含

<jsp:include page="++指定++你要包含的jsp路径">< /jsp:include>

特点:

动态包含会把包含的jsp页面翻译成java代码,通过引用的方式,将两个文件拼接在一起,本质还是多个页面

动态包含可以传递参数

<jsp:name="abc" value="qwe"/>

<%=request.getParameter("abc")%>

<%@ include file="header.jsp"%>
<h1>我是body</h1>
<%@ include file="foot.jsp"%>
<br>
<jsp:include page="header.jsp"></jsp:include>
<h1>我是body</h1>
<jsp:include page="foot.jsp"></jsp:include>

动态代码底层原理:

image-20210805215318479

请求转发

<jsp:forward page="请求转发的路径"></jsp:forward>

转发带参数:

<jsp:forward page="header.jsp">
    <jsp:param name="name" value="谭振飞"/>
    <jsp:param name="age" value="18"/>
</jsp:forward>

获取参数

<h2>我是header</h2>
<%=request.getParameter("name")%>
<%=request.getParameter("age")%>

9.jsp listener监听器

作用:监听某种事物变化,然后通过回调函数,反馈给客户(程序)做一些处理

ServletContextListener监听器

1.它可以监听ServletContext对象的创建和销毁

2.ServletContext对象在web工程启动的时候创建,在web工程停止时销毁,此过程调用ServletContextListener两个方法:

public interface ServletContextListener extends EventListener {
    default void contextInitialized(ServletContextEvent sce) {
    }
    //ServletContext创建的时候调用

    default void contextDestroyed(ServletContextEvent sce) {
    }
}
 //ServletContext销毁的时候调用

使用ServletContextListener监听器来监听ServletContext对象

1.编写一个类来实现ServletContextListener

2.实现两个回调方法

3.到web.xml配置监听器

image-20210805222922191

EL表达式

image-20211102204809148

image-20211102213912830

image-20211102213935780

image-20211102214045607

image-20211102214405784

JSTL

jsp标准标签库,为了弥补html标签的不足

核心标签:

image-20220718175852022

例子:

<%
    ArrayList<String> people=new ArrayList<>();
    people.add("1");
    people.add("2");
    people.add("3");
    people.add("4");
    request.setAttribute("list",people);
%>
<c:forEach var="people" items="${list}">
    <c:out value="${people}"></c:out>
</c:forEach>

if标签

image-20211103203625086

image-20211103203705913

choose标签

image-20211103205615755

foreach标签

image-20211103211625353

image-20211103211656036

会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话

状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学曾经来过,称之为有状态会话

一个网站怎么证明你来过:

1.客户端给客户一个信件,客户端下次来访问服务器端带上信件就可以了;cookie

2.服务器登记你来过了,下次你来的时候我来匹配你;seesion

服务器通知客户端保存键值对的一种技术

客户端有了cookie后,每次请求都发送给了服务器

每个cookie的大小不能超过4kb

cookie的创建(保存在客户端)

1.创建cookie对象:Cookie cookie=new Cookie("key","value");

2.通知客户端保存Cookie:resp.addCookie(cookie);//此过程不可省略

解决响应中文乱码问题:resp.setContentType("text/html;charset="UTF-8");

cookie创建的底层原理:

image-20210805225712769

cookie的获取

服务器获取cookie:req.getcookies();//返回cookie数组

image-20210805230631101

获取指定单个cookie:

Cookie c1=null;
for(Cookie cookie:cookies){
    if("key".equals(cookie.getName()))
        c1=cookie;
}
if(c1!=null){
    response.getWriter().write("找到了需要的cookie");
}

cookie值的修改

方案一:

1.先创建一个要修改的同名的cookie对象

2.在构造器,同时赋予新的cookie值

3.调用response.addcookie(cookie);

Cookie cookie=new Cookie("key1","newvalue");
response.addCookie(cookie);

方案二:

1.先查找到需要修改的cookie对象

2.调用setValue()方法赋予新的cookie值

3.调用response.addcookie(cookie);通知客户端保存修改

image-20210805233450955

注意:cookie的value值不能为空格,方括号,等号,逗号,双引号,斜杠,问好,汉字等,如果要使用,要是有base64编码。

cookie生命配置

指的是如何管理cookie什么时候被销毁(删除)

方法:setMaxAge(index);

当index为正数,表示在指定的秒数后过期

当index为负数,表示浏览器一关,cookie就会被删除//默认为-1

当index为零,表示立刻删除cookie

image-20210806000950026

image-20210806001107084

cookie的有效路径path的设置

path属性可以有效地过滤哪些cookie可以发送给服务器,哪些不能

path是通过请求的地址来进行有效的过滤

image-20210806001549628

Cookie cookie=new Cookie("path","path");
 cookie.setPath(request.getContextPath()+"/abc");
 response.addCookie(cookie);
 response.getWriter().write("创建了带有path路径的cookie");

Cookie值是汉字时解决乱码问题

1.先对cookie编码:

new Cookie("tzf", URLEncoder.encode("谭振飞","utf-8"));

2.再对cookie解码:

URLDecoder.decode(cookie.getValue(),"utf-8");

Session(服务器端,重点)

会话,是一个接口,用来维护一个客户端和服务器之间关联的一种技术

每个客户端都有自己的一个session会话

session会话中,我们经常用来保存用户登陆之后的信息

1.创建session和获取(id号,是否为新)

request.getSession();

第一次调用,表示创建session会话;

之后调用都是获取前面创建好的会话对象

判断request.getSession();是否为第一次调用:

isNew();

true 表示刚创建(第一次)

false 表示获取之前创建好的会话

注意:每一个会话都有一个独一无二的id

getid();

方法用来得到该方法id;

image-20210806003700675

2.session域数据的存储

request.getSession().setAttribute("key","value");
request.getSession().getAttribute("key");
//得到session
HttpSession session = req.getSession();
        String id = session.getId();
        person person = new person("谭振飞", "20");
        session.setAttribute("name",person);
        if(session.isNew()){
            resp.getWriter().write("session创建成功,id是:"+id);
        }
        else {
            resp.getWriter().write("session已经存在,id是:"+id);
        }
        session.removeAttribute("name");
//        手动注销
        session.invalidate();

3.session生命周期控制

public void setMaxlnactivelnterval(int interval)

设置session的超时时长(以秒为单位),超过指定时长(默认时长30分钟),session就会被销毁

正数设置超时时长(两次点击间隔时长)

负数表示永不超时(很少用)

如果为零,使用此会话无效,然后取消对任何绑定到它的对象绑定

public void getMaxlnactivelnterval(int interval)

获取session的超时时长

image-20210806005106053

如果想要修改个别session的超时时长,可以用session.getMaxlnactivelnterval(int interval)单独设置

image-20210806005742582

session注销

(1)手动注销:

public void invalidate();

让当前的session会话超时无效,即注销session

(2)配置生命周期自动注销:

<session-config>
<!--以分钟为单位,设置15分钟自动失效-->
    <session-timeout>15</session-timeout>
  </session-config>

4.浏览器和session 之间的关联

session技术,底层是基于cookie技术来实现的

image-20210806012053214

5.Session和Cookie的区别

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

session使用场景:

  • 保存一个登录用户信息
  • 购物车信息
  • 在整个网站中经常会使用的数据,我们将它保存在Session中

Filter过滤拦截

javaee接口

作用:拦截请求,过滤响应

filter中dofilter方法专门拦截请求的

拦截请求底层原理:

image-20210806102927690

filter基本使用

1.编写一个类实现filter接口

2.实现过滤方法dofilter();

3.到web.xml中配置filter的拦截路径

 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest httpServletRequest=(HttpServletRequest) servletRequest;
        HttpSession session=httpServletRequest.getSession();
        Object user=session.getAttribute("user");
        if(user!=null){
            //如果没有登录,跳转登录页面
            servletRequest.getRequestDispatcher("/dsm.jsp").forward(servletRequest,servletResponse);
        }
        else{
            //已经登录,放行继续访问资源
            filterChain.doFilter(servletRequest,servletResponse);
        }
    }
}
<filter>
    <filter-name>getfilter</filter-name>
    <filter-class>dsm.dsm.Getfilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>getfilter</filter-name>

    <url-pattern>/</url-pattern>
</filter-mapping>

filter生命周期

1.构造器方法

public class Getfilter implements Filter {
    public Getfilter() {
    }

2.init初始化方法

@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

第一二步在web工程启动的时候执行(filter已经创建)

3.dofilter过滤方法

每次拦截到请求就会执行

 @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

//        HttpServletRequest httpServletRequest=(HttpServletRequest) servletRequest;
//        HttpSession session=httpServletRequest.getSession();
//        Object user=session.getAttribute("user");
//        if(user!=null){
//            //如果没有登录,跳转登录页面
//            servletRequest.getRequestDispatcher("/dsm.jsp").forward(servletRequest,servletResponse);
//        }
//        else{
//            //已经登录,放行继续访问资源
//            filterChain.doFilter(servletRequest,servletResponse);
//        }
    }

4.destroy销毁

停止web工程的时候,就会执行(停止web工程,也会销毁web工程)

@Override
public void destroy() {

}

filterConfig类

filter过滤器的配置文件类,tomcat每次创建filter的时候都会创建filterconfig类

作用:

1.获取filter-nameneir

filterconfig.getfiltername();

2.获取在filter中配置的init-param初始化参数

filterconfig.getInitParamter();

3.获取servletcontent对象

filterconfig.getServletContext();

filterchan

过滤器链(多个过滤器同时执行)

特点:

1.所有filter和目标为资源默认都执行在一个线程中

  1. 多个filter共同执行的时候,他们都使用同一个request对象

image-20210806114312612

image-20210806113745178

filter的拦截路径

--精确匹配

<url-pattern>/hello</url-pattern>

--目录匹配

<url-pattern>/admin/*</url-pattern>

--后缀名匹配

<url-pattern>/*.html</url-pattern>

listener监听器

1.实体类:

ServletContext ctx = se.getSession().getServletContext();
        System.out.println(se.getSession().getId());
        Integer onlineCount = (Integer)ctx.getAttribute("OnlineCount");
        if(onlineCount==null){
            onlineCount=new Integer(1);
        }
        else {
          int count=  onlineCount.intValue();
          onlineCount=new Integer(count+1);
        }
        ctx.setAttribute("OnlineCount",onlineCount);

2.web.xml中注册配置信息

<listener>
    <listener-class>com.dsm.listener.listener</listener-class>
</listener>

3.看惊恐

JSON

(待学)

Ajax

  • Ajax=异步JavaAcript+XML
  • Ajax是一种用于创建快速动态网页的技术,通过在后台与服务器进行少数数据交换,Ajax可以使网页实现异步更新,这意味着可以不断重复加载整个网页的情况下,对网页的莫部分进行更新
  • 传统网页(不使用Ajax)如果需要更新内容,必须重载整个网页
  • Ajax不是一门新的编程语言,而是一种用于创建更快以及交互性更强的web应用程序的技术

使用jQuery需要导入jQuery,使用Vue导入Vue,两个都用,自己原生态实现

三部曲

1.编写对应处理的Controller,返回消息或者json格式的数据;

2.编写ajax请求

  1. url:Controller请求
  2. data:键值对
  3. success:回调函数

3.给Ajax绑定事件,点击.click,失去焦点onblur,键盘弹起keyup

.Http

http(超文本传输协议)是一个简单的请求响应协议,他通常运行在TCP之上

  • http1.0:客户端可以与web服务器连接后,只获取一个web资源,断开连接
  • http2.0:客户端可以与web服务器连接后,可以获取多个web资源

http相对路径和绝对路径:

image-20210805001430491

web中"/"(表示绝对路径)不同的意义

浏览器中"/"被解析成:http://ip:port/

服务器中"/"被解析成:http://ip:port/工程路径

eg:/servlet

servletContext.getRealPath("/");

request.getRequestDispatcher("/");

特殊情况:

request.sendRediect("/");虽然此时在服务器内,仍然把斜杠发送给浏览器,解析成http://ip:port/

http请求

客户端--发请求--服务器

eg百度:

image-20210730092044387

1.请求行

  • 请求方式:get,post,head,delete,put,tract...

get:请求能够携带的参数比较少,大小写有限,会在浏览器的URL地址栏显示数据内容,不安全,但高效

post:请求能够携带的参数没有限制,大小写没有限制,不会在浏览器的URL地址栏显示数据内容,安全,但不高效

  • 消息头

    image-20210730102925374

http响应

  • 服务器--响应--客户端

eg百度:

image-20210730092442278

1.响应体

image-20210730103205456

2.响应状态码

200:请求响应成功 200

3--:请求重定向(重新到--位置去)

4--:找不到资源 404

5--:服务器代码错误 500(服务器错误) 502(网关错误)

Maven

. Maven是专门用于管理和构建Java项目的工具,它的主要功能有:

  • 提供了一套标准化的项目结构
  • 提供了一套标准化的构建流程(编译,测试,打包,发布...….)
  • 提供了一套依赖管理机制

在Javaweb开发者,需要手动导入大量jar包,而maven(项目架构管理工具)就可以帮助我们导入jar包

Maven核心思想:约定大于配置

下载安装maven

环境配置变量

(未完---------------------)

jdbc

jdbc原理解释图 :

image-20211026190705018

Java DataBase Connectivity

主要在java语言中编写sql语句,对mysql数据库中的数据进行CRUD操作,是sun公司指定好的接口,降低了程序的耦合度,可以连接任意一个数据库

jar包实际就是jdbc接口的实现类,其中mysql-connector-java-5.1.23的jar包专业术语,mysql的驱动

jdbc编程六步

首先需要导入数据库依赖:


<!--mysql驱动-->
<dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

1.注册驱动(通知java程序我们即将要连接的是哪个品牌的数据库)

方式一:

Driver driver=new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);

方式二(类加载):

try {
                Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

2.获取数据库连接(java进程和mysql进程,两个进程之间的通道开启了)

方式一:

String url="jdbc:mysql://localhost:3306/bjpowernode";
String user="root";
String password="123456";
conn=DriverManager.getConnection(url,user,password);

方式二(资源绑定器):

配置文件资源包resources下的bd包:

driver:...

url:...

user:...

passworld:...

java类:

ResourceBundle bundle=ResourceBundle.getbundle("resources/db")

String driver=bundle.getString("driver");

String url=bundle.getSrting("url")

String user=bundle.getString("user")

String password=bundle.getString("password")

优点:配置文件改变时,不用动代码

3.获取数据库操作对象(用这个对象执行sql)

stmt =conn.createStatement();

4.执行sql操作语句(执行crud)

//增
String insert="insert into user_info(deptno,dname,loc)value(50,'销售部','北京')";
int count=stmt.executeUpdate(insert);
//改
String updataSql="updata deptno set dname='人事部',loc='天津' where deptno=50";
int count1=stmt.executeUpdate(updataSql);
//删
String deleteSql="delete from user_info where deptno=50";
int count3=stmt.executeUpdate(deleteSql);
//查
String str="select *  from user_info order by id";
rs= stmt.executeQuery(str);
while (rs.next()){
        String empno=  rs.getString(1);
        String empname=  rs.getString(2);
        String sal=  rs.getString(3);
        System.out.println(empname+","+empno+"," +sal);

5.处理查询结果集(如果第四步是select语句,才有第五步)

//根据下标取值
//                int empno1=rs.getInt(1);
//                String ename=rs.getString(2);
                //根据查询结果的列名取值,健壮,username不是表中字段的名字,是查询结果的列名即select 后的名字
//                int empno1=rs.getInt("id");
//                String ename=rs.getString("username");

6.释放资源(关闭资源)

 try {
        stmt.close();
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
}
if(conn!=null){
    try {
        conn.close();
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }

DriverManger.registerdriver(new com.mysql.jdbc.driver)

conn=DriverManager.getConnection(......)

ste=conn.creatStement()

String str=''

re=ste.executeQuery(str)

sql注入

java.sql.Statement接口特点:先进行字符串拼接,然后再进行sql语句的传值

优点:使用Statement可以在sql语句的拼接

缺点:由于拼接的存在,导致可能给不法分子机会。导致sql注入()

java.sql.PrepareStatement(预编译数据库操作对象)接口特点:先进行sql语句的编译,然后再进行sql语句的传值。

优点:避免sql注入

缺点:没有办法进行sql语句的拼接,只能给sql语句赋值

避免sql注入方法

image-20211029212612170

image-20211029212743265

prepareStatement对字符进行转义和预编译,来预防SQL注入问题

jdbc事物

要么成功,要么失败

ACID原则:保证数据的安全

  1. 开启事务
  2. 事务提交
  3. 事务回滚
  4. 关闭事物

junit

单元测试,可以用注解@test来代替main方法,来实现不需要main方法就可运行class类

1.先导入Junit包

 <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

2.使用@test注解

@test注解只在方法上有效

public class test {
    @Test
    public void test(){
        
    }
}

jdbc默认情况支持自动提交,在实际开发中必须将jdbc的自动提交机制关掉,改成手动提交,当一个完整的事物结束之后,再提交

解决方法:

conn.setAutoCommit(false);关闭自动提交机制

image-20211029220240140

conn.commmit();手动提交

image-20211029220306529

conn.rollback();手动回滚

image-20211029220327028

javabean

java写的可重用组件,减少代码的冗余,相同代码的功能不必重写

实体类

javabean特定的写法:

  • 属性必须有一个无参构造
  • 属性必须私有化
  • 必须有对应的get/set法

一般用来和数据库的字段做·映射

  • 表-->类
  • 字段-->属性
  • 行记录-->对象
<jsp:useBean id="people" class="com.dsm.jsp01.people"/>
<jsp:setProperty name="people" property="age" value="18"/>
<jsp:setProperty name="people" property="name" value="tzf"/>
姓名:<jsp:getProperty name="people" property="name"/>
年龄:<jsp:getProperty name="people" property="age"/>

mvc开发模式

演变历史:

image-20211102200029411

image-20211102200250328

image-20211102201344912

image-20211102201302461

image-20220719103127545

文件上传与下载

1、准备工作

采用Apache的开源工具common-fileupload这个文件上传组件。

common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。

(https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload/1.3.3)

<!--maven相关jar包导入-->
<!-- 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)

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>
 

2、使用类介绍

【文件上传注意事项】

1、为保证服务器的安全,上传的文件应放在外界无法访问的目录下,如WEN-INF。

2、为防止同名文件产生覆盖现象,要为文件指定一个唯一的文件名。(-时间戳 -uuid -md5 -位运算算法 )

3、要对上传文件的大小进行限制。

4、限制上传文件的类型,收到文件时,判断文件名十分合法。

HTML中

表单中如果包含一个文件上传项的话,这个表单的entype属性必须设置为multipart/form-data

<form action="${pageContext.request.contextPath}/upload.do" method="post"enctype="multipart/form-data">
    <p>用户名:<input type="text" name="username" placeholder="请填写用户名"></p>
    <p>上传文件:<input type="file" name="filename"></p>
    <p><input type="submit" value="提交"><input type="reset" value="重置"></p>

【需要用到的类详解】

ServletFileUpload负责处理上传的文件数据,并将表单中的每个输入项封装成一个FileItem对象,在使用ServletFileUpload对象解析请求时需要DiskFileItemFactory对象。所以,我们需要在进行解析工作前构造好DiskFileItemFactory对象,通过ServletFileItem对象的构造方法或setFileItemFactory()设置ServletFileUpload对象的fileItemFactory属性。

public class UploadFileServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        //判断上传的表单是普通表单还是带文件的表单,是返回true,否返回false;
        if (!ServletFileUpload.isMultipartContent(request)){
            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 file = new File(tmppath);
        if (!file.exists()){
            file.mkdir();//如果目录不存在就创建这样临时目录
        }
        //处理上传的文件一般需要通过流来获取,我们可以通过request.getInputstream(),原生态文件上传流获取,十分麻烦
        //但是我们都建议使用Apache的文件上传组件来实现,common-fileupload,它需要依赖于common-io组件;
 
 
        try {
            //1、创建DiskFileItemFactory对象,处理文件上传路径或限制文件大小
            DiskFileItemFactory factory = gteDiskFileItemFactory(file);
            //2、获取ServletFileUpload
            ServletFileUpload upload = getServletFileUpload(factory);
            //3、处理上传文件
            String msg = uploadParseRequest(upload,request,uploadpath);
            //Servlet请求转发消息
            request.setAttribute("msg",msg);
            request.getRequestDispatcher("/info.jsp").forward(request,response);
        }catch (FileUploadException e){
            e.printStackTrace();
        }
    }
    public static DiskFileItemFactory gteDiskFileItemFactory(File file){
        //1、创建DiskFileItemFactory对象,处理文件上传路径或限制文件大小
        DiskFileItemFactory factory = new DiskFileItemFactory();
 
 
        //通过这个工厂设置一个缓冲区,当上传的文件大小大于缓冲区的时候,将它放到临时文件中;
        factory.setSizeThreshold(1024 * 1024);//缓冲区大小为1M
        factory.setRepository(file);
        return factory;
    }
    public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){
        //2、获取ServletFileUpload
        ServletFileUpload upload = new ServletFileUpload(factory);
        //监听文件上传进度
        upload.setProgressListener(new ProgressListener() {
            @Override
            public void update(long pBytesRead, long lpContentLenght, int i) {
                //pBytesRead:已读取到的文件大小
                //pContentLenght:文件大小
                System.out.println("总大小:"+lpContentLenght+"已上传:"+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对象
        List<FileItem> fileItems = upload.parseRequest(request);
        for (FileItem fileItem : fileItems) {
            if (fileItem.isFormField()){ //判断是普通表单还是带文件的表单
                //getFieldName指的是前端表单控件的name
                String name = fileItem.getFieldName();
                String value = fileItem.getString("UTF-8");//处理乱码
                System.out.println(name+":"+value);
            }else {//判断它是带文件的表单
 
 
                //======================处理文件=======================//
 
 
                //拿到文件的名字
                String uploadFileName = fileItem.getName();
                System.out.println("上传的文件名:"+uploadFileName);
 
 
                if (uploadFileName.trim().equals("")) continue;
 
 
                //获得上传的文件名,例如/img/girl/ooa.jpg,只需要ooa,其前面的后面的都不需要
                String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
                //获得文件的后缀名
                String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
                /*
                 * 如果后缀名 fileExtName 不是我们需要的
                 *就直接return,不处理,告诉用户类型不对
                 * */
                System.out.println("文件信息【文件名:"+fileName+"文件类型:"+fileExtName+"】");
 
 
                //可以使用UUID(唯一通用识别码)来保证文件名的统一
                String uuidFileName = UUID.randomUUID().toString();
 
 
 
 
                //=======================传输文件=========================//
                //获得文件上传的流
                InputStream inputStream = fileItem.getInputStream();
 
 
                //创建一个文件输出流
                FileOutputStream fos = new FileOutputStream(uploadpath + "/" + uuidFileName +"."+ fileExtName);
 
 
                //创建一个缓冲区
                byte[] buffer = new byte[1024 * 1024];
 
 
                //判断是否读取完毕
                int len;
 
 
                //如果大于0,说明还存在数据
                while ((len=inputStream.read(buffer))>0){
                    fos.write(buffer,0,len);
                }
 
 
                //关闭流
                fos.close();
                inputStream.close();
 
 
                msg = "文件上传成功!";
                fileItem.delete();//上传成功,清除临时文件
            }
        }
 
 
        return msg;
    }
}

3、其他

重点了解HashMap和线程底层源码

uuid是如何实现的

邮件发送

1、传输协议:

  • SMTP协议

    处理用户邮件发送的请求。

  • POP3协议

    处理用户邮件接收请的求。

2、导包:

mail-1.4.7.jar

activation-1.1.1.jar

3、过程:

img

4、代码:

[复制代码](javascript:void(0)😉

import com.sun.mail.util.MailSSLSocketFactory;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

public class sendMail01 {
    //简单邮件:纯文本内容
    //复杂邮件:文本+图片+附件

    //要发送邮件需要获取协议,开启POP3和SMTP服务
    public static void main(String[] args) throws Exception {

        Properties prop = new Properties();//创建一封邮件
        //以下三项的Key的值都是固定的
        prop.setProperty("mail.host","smtp.qq.com");//设置邮件服务器
        prop.setProperty("mail.transport.protocol","smtp");//设置邮件发送协议
        prop.setProperty("mail.smtp.auth","true");//需要验证用户名和密码

        //如果是QQ邮箱,还要设置SSL加密,加上以下代码即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        prop.put("mail.smtp.ssl.enable","true");
        prop.put("mail.smtp.ssl.socketFactory",sf);

        //==========使用JavaMail发送邮件的6个步骤======

        //1、创建定义整个应用程序所需要的环境信息的Session对象
        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            public PasswordAuthentication getPasswordAuthentication(){
                //发件人邮箱的用户名和授权码(只有qq是授权码,其它的是密码)
                return new PasswordAuthentication("1612893803@qq.com","授权码");
            }
        });
        //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
        session.setDebug(true);
        
        //2、通过Session得到transport对象
        Transport ts = session.getTransport();

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

        //创建邮件对象
        MimeMessage message = new MimeMessage(session);
        //指明邮件的发件人
        message.setFrom(new InternetAddress("1612893803@qq.com"));
        //指明邮件的收件人
        message.setRecipient(Message.RecipientType.TO,new InternetAddress("212694926@qq.com"));
        //邮件的标题
        message.setSubject("只是一个普通的纯文本邮件");
        //邮件的文本内容
        message.setContent("你好哇,我来了!","text/html;charset=UTF-8");
        //5、发送邮件
        ts.sendMessage(message,message.getAllRecipients());
        //6、关闭连接
        ts.close();
    }
}

[复制代码](javascript:void(0)😉

5、带附件:

附件格式包含关系:

img

[复制代码](javascript:void(0)😉

import com.sun.mail.util.MailSSLSocketFactory;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.util.Properties;

public class sendMail02 {
    //简单邮件:纯文本内容
    //复杂邮件:文本+图片+附件

    /*
    *MimeMessage类表示整封邮件。
    *MimeBodyPart类表示邮件的一个MIME消息。
    *MimeMultipart类表示一个由多个MIME消息组合成的组合MIME消息。
    */

    //要发送邮件需要获取协议,开启POP3和SMTP服务
    public static void main(String[] args) throws Exception {

        Properties prop = new Properties();//创建一封邮件
        //以下三项的Key的值都是固定的
        prop.setProperty("mail.host","smtp.qq.com");//设置邮件服务器
        prop.setProperty("mail.transport.protocol","smtp");//设置邮件发送协议
        prop.setProperty("mail.smtp.auth","true");//需要验证用户名和密码

        //如果是QQ邮箱,还要设置SSL加密,加上以下代码即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        prop.put("mail.smtp.ssl.enable","true");
        prop.put("mail.smtp.ssl.socketFactory",sf);

        //==========使用JavaMail发送邮件的6个步骤======
        
        //变量名字定义的有点乱,不想改了。将就下吧

        //1、创建定义整个应用程序所需要的环境信息的Session对象
        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            public PasswordAuthentication getPasswordAuthentication(){
                //发件人邮箱的用户名和授权码
                return new PasswordAuthentication("1612893803@qq.com","授权码");
            }
        });
        //开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
        session.setDebug(true);

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

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

        //创建邮件对象
        MimeMessage message = new MimeMessage(session);
        //指明邮件的发件人
        message.setFrom(new InternetAddress("1612893803@qq.com"));
        //指明邮件的收件人
        message.setRecipient(Message.RecipientType.TO,new InternetAddress("212694926@qq.com"));
        //邮件的标题
        message.setSubject("这是一个有文本、图片、附件的邮件");
        //邮件的内容
       //=================================================
       //准备图片数据 DataHandler:处理除文本外的数据
        MimeBodyPart image = new MimeBodyPart();
        DataHandler dh = new DataHandler(new FileDataSource("C:\\Users\\Think\\Documents\\image-20200220200136289.png"));
        image.setDataHandler(dh);
        image.setContentID("xx.png");//设置图片ID
        //ContentID用于为“multipart/related”组合消息中的内嵌资源指定一个唯一标识号,在HTML格式的正文中可以使用这个唯一标识号来引用该内嵌资源。
        //注意,在引用Content-ID头字段标识的内嵌资源时,要在资源的唯一标识号前面加上“cid:”,以说明要采用唯一标识号对资源进行引用。

        //准备正文数据
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("这是一个带图片、文本、附件<img src='cid:xx.png'>的邮件","text/html;charset=UTF-8");

        //准备附件数据
        MimeBodyPart accessory = new MimeBodyPart();
        DataHandler dh2 = new DataHandler(new FileDataSource("C:\\Users\\Think\\Pictures\\Saved Pictures\\illust_70110900_20191209_012234.jpg"));
        accessory.setDataHandler(dh2);
        accessory.setFileName(MimeUtility.encodeText("yan"));//给附件一个名字,发过去显示的就是这个设定的名字||MimeUtility.encodeText("")解决附件发送过去乱码;

        //*****************************!!!!!!!**********************
            /*
                 MimeBodyPart:表示复杂邮件的一个组成部分,它可以表示文本,附件,图片
                 DataHandler:表示可以读取图片或附件
                 MimeMultipart:表示二个邮件组成部分的关系,文本和图片的关系是"related"关系
                 Content-ID:表示图片的编号
                 related:图片|| mixed:附件
             */
        //*****************************!!!!!!!**********************

        //拼接图片和文本
        MimeMultipart mm = new MimeMultipart();
        mm.addBodyPart(text);
        mm.addBodyPart(image);
        mm.setSubType("related");

        //将文本+图片封装成邮件的组成部分,即将关系看作成一个部分
        MimeBodyPart context = new MimeBodyPart();
        context.setContent(mm);

        //把附件也加上
        MimeMultipart file = new MimeMultipart();
        file.addBodyPart(context);
        file.addBodyPart(accessory);
        file.setSubType("mixed");

        //放到消息中
        message.setContent(file);//把编辑好的内容放入消息中
        message.saveChanges();//保存修改!


        //=================================================
        //5、发送邮件
        ts.sendMessage(message,message.getAllRecipients());//message:发送的消息||message.getAllRecipients():获取保存在里面的地址
        //6、关闭连接
        ts.close();
    }
     //对于,复杂类型的邮件,位置关系特别注意和加入的顺利要一致
}

[复制代码](javascript:void(0)😉

后续学习

image-20220801231952402

image-20220801232032299

image-20220801231807218

image-20220801232148431

image-20220801232449256

image-20220801232501953

image-20220801232602827