JavaWeb笔记-程序员宅基地

技术标签: JavaEE开发  java  前端  服务器  

JavaWeb

笔记备忘

1、Web基本概念

web开发:

  • web:网页

  • 静态web

    • html,css
    • 提供给所有人看内容不会变化
  • 动态web

    • 淘宝等几乎所有网站
    • 内容会根据不同的人发生变化
    • 技术栈:Servlet/JSP,ASP,PHP

在java中,动态web资源开发中的技术统称为JavaWeb;

2、Servlet

2.1、Servlet简介

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

2.2、Servlet原理

Servlet是由Web服务器调用,web服务器收到浏览器的请求之后,会:

在这里插入图片描述

2.3、Mapping问题
  1. 一个servlet可以指定一个映射路径

    <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>/hello1</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello2</url-pattern>
    </servlet-mapping>
    
  3. 一个servlet可以指定通用映射路径

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

    *----->在正则表达式中表示通配符

  4. 指定一些后缀或前缀

    <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    

    这里的.do是后缀,后缀可以设置成任意值,但是*前不能加反斜杠

  5. 默认请求路径(不建议使用)

    <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/*</url-pattern>
    </servlet-mapping>
    
  6. 优先级问题

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

2.4、ServletContext

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

应用:

1、共享数据

在此servlet中存放的数据,可以在另一个servlet中得到

2、获取初始化参数

getInitParam

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        ServletContext context = this.getServletContext();
        String jdbcurl = context.getInitParameter("jdbcurl");
        resp.getWriter().print(jdbcurl);

    }
3、请求转发

在这里插入图片描述

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        ServletContext context = this.getServletContext();
        context.getRequestDispatcher("/getp").forward(req,resp);
    }
4、读取资源文件

Properties

  • 在java目录下新建properties
  • 在resources目录下新建properties

发现:都被打包到同一个路径下:classes,我们称此路径为类路径

思路:需要一个文件流

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        ServletContext context = this.getServletContext();
        //读取资源文件
        InputStream is = context.getResourceAsStream("/WEB-INF/classes/db.properties");
        Properties prop = new Properties();
        prop.load(is);
        String username = prop.getProperty("username");
        String password = prop.getProperty("password");
        resp.getWriter().println(username);
        resp.getWriter().println(password);

    }
2.5、HttpServletResponse

web服务器收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletResponse。

  • 如果要获取客户端请求过来的参数:找HttpServletRequest
  • 如果要客户端的一些信息,找HttpServletResponse
常见应用
1、向浏览器输出消息
2、下载文件
  1. 获取下载文件的路径
  2. 下载的文件名
  3. 设置想办法让浏览器能够支持下载我们需要的东西
  4. 获取下载文件的输入流
  5. 创建缓冲区
  6. 获取OutputStream对象
  7. 将FileOutputStream流写入buffer缓冲区
  8. 使用OutputStream将缓冲区的数据输出到客户端

java下载文件

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        //  1. 获取下载文件的路径
        //String realPath = this.getServletContext().getRealPath("/1.png");
        String realPath = "D:\\Project\\Java-learn-all\\Response\\src\\main\\resources\\1.png";
        //resp.getWriter().print("下载的文件名为:"+realPath);
        System.out.println("下载的文件名为:"+realPath);
        //  2. 下载的文件名
        String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
        //  3. 设置想办法让浏览器能够支持下载我们需要的东西--下载中文文件名文件时,使用URLEncoder,否则中文文件名可能无法显示
        resp.setHeader("Content-disposition","attachment;filename"+URLEncoder.encode(fileName,"UTF-8"));
        //  4. 获取下载文件的输入流
        FileInputStream in = new FileInputStream(realPath);
        //  5. 创建缓冲区
        int len = 0;
        byte[] buffer = new byte[1024];
        //  6. 获取OutputStream对象
        ServletOutputStream out = resp.getOutputStream();
        //  7. 将ServletOutputStream流写入buffer缓冲区
        while((len=in.read(buffer)) > 0)
        {
    
            out.write(buffer,0,len);
        }
        out.close();
        in.close();
    }
3、验证码功能
  • 前端实现
  • 后端实现:需要用到java的图片类来生成图片
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        //验证码功能
        //浏览器每三秒刷新一次
        resp.setHeader("refresh","0.5");
        //在内存中创建一个图片
        BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
        //设置背景颜色
        Graphics2D g = (Graphics2D) image.getGraphics();
        g.setColor(Color.white);
        g.setFont(new Font(null,Font.BOLD,20));
        g.drawString(makeNum(),0,20);
        //告诉浏览器这个请求的打开方式
        resp.setContentType("image/jpeg");
        resp.setDateHeader("expires",-1);
        resp.setHeader("Cache-Control","no-cache");
        resp.setHeader("Pragma","no-cache");
        //图片写进浏览器
        ImageIO.write(image,"jpg",resp.getOutputStream());
    }
    private String makeNum()
    {
    
        Random random = new Random();
        String num = random.nextInt(9999999)+"";
        StringBuffer sb = new StringBuffer();
        for(int i = 0;i < 7-num.length();i++)
        {
    
            sb.append("0");
        }
        num = sb.toString()+num;
        return num;
    }
4、实现重定向

在这里插入图片描述

重定向定义:一个web资源收到客户端请求之后,会通知客户端去访问另一个web资源,这个过程叫做重定向。

void sendRedirect(String var1) throws IOException;
resp.sendRedirect("/此处写路径")

常见场景

  • 用户登录

面试题:请聊聊重定向和转发的区别?

相同点

  • 页面都会跳转

不同点

  • 请求转发时,url不会产生变化 307
  • 重定向时候,url地址栏会发生变化 302
2.6、HttpServletRequest

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

1、获取前端参数
getParameter
2、请求转发–注意与ServletContext的请求转发的区别
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        resp.setCharacterEncoding("utf-8");
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobbies = req.getParameterValues("hobby");
        System.out.println("----------------------------------------");
        System.out.println(Arrays.toString(hobbies));
        System.out.println(username+" : "+password);
        System.out.println("----------------------------------------");

        //这里的 / 代表当前web应用---不用加项目路径的/r
        req.getRequestDispatcher("/success.jsp").forward(req,resp);
        
    }

3、Cookie和Session

3.1、会话

会话:用户打开一个浏览器,访问多个web资源,关闭浏览器的过程称为会话。

有状态会话

网站如何证明有人访问过

客户端 服务端

  1. 服务器给客户端一个证明,客户端下次访问时只要带上证明即可;cookie
  2. 服务器已登记,下次同一用户再次访问时,直接匹配。
3.2、保存会话的两种技术

cookie

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

session

  • 服务器技术,利用此技术,保存会话信息,把信息和数据放在Session中。

网站登陆过后,下次再访问自动登录。

3.3、Cookie

1.从请求中得到cookie信息

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

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        //解决中文乱码问题
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
		resp.setHeader("content-type","text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();

        //从请求中获取cookie
        Cookie[] cookies = req.getCookies();
        if(cookies != null)
        {
    
            out.print("上一次访问的时间为:");
            for(int i = 0;i < cookies.length;i++)
            {
    
                if(cookies[i].getName().equals("lastlogintime"))
                {
    
                    long time = Long.parseLong(cookies[i].getValue());
                    Date date = new Date(time);
                    out.write(date.toGMTString());
                }
            }
        }
        else{
    
            out.print("this is the first time you access this web");
        }

        //服务器给客户端响应一个cookie
        Cookie cookie = new Cookie("lastlogintime",System.currentTimeMillis()+"");
        //设置cookie的有效期
        cookie.setMaxAge(48*60*60);
        resp.addCookie(cookie);
    }

cookie:一般存在本地用户目录下的Appdata中

一个网站的Cookie是否存在上限

  • 一个cookie只能存放一个信息
  • 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie
  • cookie大小有限制4kb
  • 300个cookie浏览器上限

删除cookie

  • 不设置有效期,关闭浏览器,自动失效;
  • 设置有效时间为0;

编码解码

URLEncoder.encode(string,"utf-8")
URLDecoder.decode(    ,"utf-8")

在这里插入图片描述

3.4、Session(重点)

Session:服务器会给每一个用户(浏览器)创建一个Session对象。可以保存信息。一个浏览器对应一个Session,只要不关闭浏览器。

Session和Cookie的区别

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

使用场景:

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

过期时间:可以在web.xml中设置,

在这里插入图片描述

在这里插入图片描述

4、JSP

4.1 含义

JSP:Java Server Pages

JSP与HTML的区别:

  • HTML只给用户提供静态数据
  • JSP中可以嵌入JAVA代码,为用户提供动态数据
4.2 JSP原理

执行的过程是什么

浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!

JSP最终也会被转化为一个JAVA类

JSP本质上就是一个Servlet

在这里插入图片描述

4.3 JSP的基本语法

支持java所有语法,即可以嵌入java代码。

jsp脚本片段:<% java代码 %>

jsp表达式: <%=变量或者等式%>

jsp声明: <%! %>—会被编译到jsp对应的java文件的类中,其他的就会生成到jspService的方法中。

JSP的注释在客户端不显示,HTML注释会显示。

4.4 JSP指令
<%@page args.... %>
<%@include file="" %> ---->公有信息可以这么导入,比如网页的头部和脚部,相当于吧代码导入

JSP标签

<jsp:include page="">  本质是拼接页面,所以其他文件中的变量与本文件有重名也可以
4.5 9大内置对象
  • PageContext
  • Request
  • Resopnse
  • Session
  • Application(ServletContext)
  • config(ServletConfig)
  • out
  • page
  • exception
4.6、JSP标签,JSTL标签,EL表达式

依赖

<!-- JSTL依赖   -->
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
    <dependency>
      <groupId>javax.servlet.jsp.jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/taglibs/standard -->
    <dependency>
      <groupId>taglibs</groupId>
      <artifactId>standard</artifactId>
      <version>1.1.2</version>
    </dependency>

EL表达式:${ }

  • 取数据
  • 执行运算
  • 获取web前端开发常用对象
JSP标签
<jsp:forward page="/jsptag2.jsp">
    <jsp:param name="name" value="小名"/>
    <jsp:param name="age" value="19"/>
</jsp:forward>
JSTL标签

参考:https://www.runoob.com/jsp/jsp-jstl.html

  • 核心标签
  • 格式化标签
  • SQL 标签
  • XML 标签

在tomcat中也需要引入jstl的包

5、JavaBean

实体类

JavaBean有特定的写法:

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

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

ORM:对象关系映射

6、MVC三层架构

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

6.1、早些年

在这里插入图片描述

用户直接访问控制层,控制层可以直接操作数据库

弊端:程序臃肿,不利于维护

6.2、MVC三层

在这里插入图片描述

Model

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

View

  • 展示数据
  • 提供连接发起Servlet请求

Controller

  • 接收用户请求
  • 交给业务层处理相应的代码
  • 控制视图跳转

7、Filter(重点)

Filter:过滤器,过滤网站数据

  • 处理中文乱码
  • 登录验证

在这里插入图片描述

1、导包

2、编写过滤器

public class CharacterEncodingFilter implements Filter {
    

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
        System.out.println("CharacterEncodingFilter启动");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    
            request.setCharacterEncoding("utf-8");
            response.setCharacterEncoding("utf-8");
            response.setContentType("text/html;charset=UTF-8");
            chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
    
        System.out.println("CharacterEncodingFilter销毁");
    }
}

在web.xml中配置

<filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.future.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>

8、监听器

实现监听器

  • 实现接口
  • web.xml中配置监听器
public class OnlineCountLisener implements HttpSessionListener {
    

    @Override
    public void sessionCreated(HttpSessionEvent se) {
    
        ServletContext ctx = se.getSession().getServletContext();
        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);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
    
        ServletContext ctx = se.getSession().getServletContext();
        Integer onlineCount = (Integer) ctx.getAttribute("OnlineCount");
        if(onlineCount == null)
        {
    
            onlineCount = new Integer(0);
        }else{
    
            int count = onlineCount.intValue();
            onlineCount = new Integer(count-1);
        }
        ctx.setAttribute("onlineCount",onlineCount);
    }
}

9、JDBC

jdbc:java连接数据库
在这里插入图片描述

jar包支持

  • java.sql
  • javax.sql
  • mysql-conneter-java 连接驱动,必须要导入

maven中导入jar包

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.22</version>
</dependency>

mysql连接,参考https://www.runoob.com/java/java-mysql-connect.html

mysql8.0版本和5.X版本有些许不同

步骤

String url = "jdbc:mysql://localhost:3306/database?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";
String username = "root";
String password = "*******";

//1、加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2、连接数据库
Connection connection = DriverManager.getConnection(url, username, password);
//3、向数据库发送sql对象
Statement statement = connection.createStatement();
//4、编写sql语句
String sql = "select * from student";
//5、执行查询sql
ResultSet rs = statement.executeQuery(sql);
while(rs.next())
{
    
    System.out.println("rank = "+rs.getObject("rank"));
    System.out.println("class = "+rs.getObject("class"));
    System.out.println("name = "+rs.getObject("name"));
    System.out.println("score = "+rs.getObject("score"));
}

//6、关闭资源,先开后关
rs.close();
statement.close();
connection.close();
事物

要么都成功,要么都失败

ACID原则:保证数据的安全

开启事物
事物提交 commit()
事物回滚 rollback()
关闭事物
//开启事物
connection.setAutoCommit(false);
Junit:单元测试

简单使用

@Test注解只有在方法上有效,只要加了这个注解就可以直接运行。

————----————JavaWeb完结——————————

拓展

10、文件上传

public class FileServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    

        //判断上传的是普通表单还是带文件的表单
        if (!ServletFileUpload.isMultipartContent(req)){
    
            return;//普通表单直接结束
        }
        //创建上传文件的保存路径,放在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();
        }

        //处理上传的文件,一般用流来获取,但是比较麻烦,这里使用Apache的文件上传组件来实现,common-fileupload

        try {
    
            //1.创建DiskFileItemFactory对象,处理文件上传路径或者大小限制
            DiskFileItemFactory factory = getDiskFileItemFactory(tmpFile);
            //2.获取ServletFileUpload
            ServletFileUpload upload = getServletFileUpload(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);

        return factory;
    }

    public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory){
    
        ServletFileUpload upload = new ServletFileUpload(factory);

        //监听上传的进度
        upload.setProgressListener(new ProgressListener() {
    
            @Override
            public void update(long l, long l1, int i) {
    
                System.out.println("总大小:"+l1+" 已上传:"+l);
            }
        });

        //处理乱码
        upload.setHeaderEncoding("UTF-8");
        //设置单个文件的最大值
        upload.setFileSizeMax(1024*1024*10);
        //设置总共能够上传文件的大小
        upload.setSizeMax(1024*1024*100);

        return upload;
    }
    public static String uploadParseRequest(ServletFileUpload upload,HttpServletRequest req,String uploadPath) throws FileUploadException,IOException{
    
        String msg = "";
        //3.处理上传文件
        //前端请求解析。封装成一个FileItem对象,需要从ServletFileUpload获取
        try {
    
            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 uploadFileName = fileItem.getName();
                    System.out.println("上传的文件名:"+uploadFileName);
                    if(uploadFileName.trim().equals("")||uploadFileName == null){
    
                        continue;
                    }
                    //获得上传文件名
                    String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/")+1);
                    //获取后缀名
                    String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".")+1);
                    System.out.println("文件信息[件名: " + fileName + " ---文件类型" + fileExtName + "]");
                    //使用UUID(唯一识别通用码)保证文件名的唯一
                    String uuidPath = UUID.randomUUID().toString();

                    //======存放地址
                    //文件真实存在的路径
                    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;
                    while((len = inputStream.read(buffer)) > 0){
    
                        fos.write(buffer,0,len);
                    }
                    //关闭流
                    fos.close();
                    inputStream.close();
                    //上传成功,清除临时文件
                    msg = "文件上传成功";
                    fileItem.delete();
                }
            }

        } catch (Exception e) {
    
            msg = "文件上传失败";
            e.printStackTrace();
        }

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

利用maven创建的项目,保存的文件在Tomcat目录下的webapps中。普通的web项目,保存的文件在target目录下/out目录下。

11、邮件发送

11.1、普通邮件发送

纯文本邮件发送

mport com.sun.mail.util.MailSSLSocketFactory;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.*;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;

public class SendMail {
    
    public static void main(String[] args) throws Exception {
    
        Properties prop = new Properties();
        prop.setProperty("mail.host","smtp.qq.com");//设置QQ邮件服务器
        prop.setProperty("mail.transport.protocol","smtp");//邮件发送协议
        prop.setProperty("mail.smtp.auth","true");//需要验证用户名密码

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

        //使用Java发送邮件的5个步骤
        //1.创建定义整个应用程序所需的环境信息的Session对象
        //QQ才有!其他邮箱就不用
        Session session=Session.getDefaultInstance(prop, new Authenticator() {
    
            public PasswordAuthentication getPasswordAuthentication() {
    
                //发件人邮件用户名、授权码
                return new PasswordAuthentication("[email protected]","qpszlppmatiweiaa");
            }
        });
        //开启session的debug模式,这样可以查看到程序发送Email的运行状态
        session.setDebug(true);
        //2.通过session得到transport对象
        Transport ts=session.getTransport();

        //3.使用邮箱的用户名和授权码连上邮件服务器
        ts.connect("smtp.qq.com","[email protected]","qpszlppmatiweiaa");

        //4.创建邮件:写文件
        //注意需要传递session
        MimeMessage message=new MimeMessage(session);
        //指明邮件的发件人
        message.setFrom(new InternetAddress("[email protected]"));
        //指明邮件的收件人
        message.setRecipient(Message.RecipientType.TO,new InternetAddress("[email protected]"));
        //邮件标题
        message.setSubject("发送的标题");
        //邮件的文本内容
        message.setContent("内容","text/html;charset=UTF-8");

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

        //6.关闭连接
        ts.close();
    }
}
11.2、复杂邮件发送

带有附件的邮件发送

public class SendMail3 {
    
    public static void main(String[] args) throws Exception {
    
        //包含文件的发送
        //创建一个配置文件保存并读取信息
        Properties properties = new Properties();

        //设置qq邮件服务器
        properties.setProperty("mail.host","smtp.qq.com");
        //设置发送的协议
        properties.setProperty("mail.transport.protocol","smtp");
        //设置用户是否需要验证
        properties.setProperty("mail.smtp.auth", "true");


        //=================================只有QQ存在的一个特性,需要建立一个安全的链接
        // 关于QQ邮箱,还要设置SSL加密,加上以下代码即可
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        properties.put("mail.smtp.ssl.enable", "true");
        properties.put("mail.smtp.ssl.socketFactory", sf);

        //=================================准备工作完毕

        //1.创建一个session会话对象;
        Session session = Session.getDefaultInstance(properties, new Authenticator() {
    
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
    
                return new PasswordAuthentication("[email protected]","qpszlppmatiweiaa");
            }
        });

        //可以通过session开启Dubug模式,查看所有的过程
        session.setDebug(true);


        //2.获取连接对象,通过session对象获得Transport,需要捕获或者抛出异常;
        Transport tp = session.getTransport();

        //3.连接服务器,需要抛出异常;
        tp.connect("smtp.qq.com","[email protected]","qpszlppmatiweiaa");

        //4.连接上之后我们需要发送邮件;
        MimeMessage mimeMessage = imageMail(session);

        //5.发送邮件
        tp.sendMessage(mimeMessage,mimeMessage.getAllRecipients());

        //6.关闭连接
        tp.close();

    }


    public static MimeMessage imageMail(Session session) throws MessagingException {
    

        //消息的固定信息
        MimeMessage mimeMessage = new MimeMessage(session);

        //邮件发送人
        mimeMessage.setFrom(new InternetAddress("[email protected]"));
        //邮件接收人,可以同时发送给很多人,我们这里只发给自己;
        mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress("[email protected]"));
        mimeMessage.setSubject("我也不知道是个什么东西就发给你了"); //邮件主题


        /*
        编写邮件内容
        1.图片
        2.附件
        3.文本
         */

        //图片
        MimeBodyPart body1 = new MimeBodyPart();
        body1.setDataHandler(new DataHandler(new FileDataSource("src/resources/1.png")));
        body1.setContentID("yhbxb.png"); //图片设置ID

        //文本
        MimeBodyPart body2 = new MimeBodyPart();
        body2.setContent("请注意,我不是广告<img src='cid:yhbxb.png'>","text/html;charset=utf-8");

        //附件
        MimeBodyPart body3 = new MimeBodyPart();
        body3.setDataHandler(new DataHandler(new FileDataSource("src/resources/log4j.properties")));
        body3.setFileName("log4j.properties"); //附件设置名字

        MimeBodyPart body4 = new MimeBodyPart();
        body4.setDataHandler(new DataHandler(new FileDataSource("src/resources/1.txt")));
        body4.setFileName(""); //附件设置名字

        //拼装邮件正文内容
        MimeMultipart multipart1 = new MimeMultipart();
        multipart1.addBodyPart(body1);
        multipart1.addBodyPart(body2);
        multipart1.setSubType("related"); //1.文本和图片内嵌成功!

        //new MimeBodyPart().setContent(multipart1); //将拼装好的正文内容设置为主体
        MimeBodyPart contentText =  new MimeBodyPart();
        contentText.setContent(multipart1);

        //拼接附件
        MimeMultipart allFile =new MimeMultipart();
        allFile.addBodyPart(body3); //附件
        allFile.addBodyPart(body4); //附件
        allFile.addBodyPart(contentText);//正文
        allFile.setSubType("mixed"); //正文和附件都存在邮件中,所有类型设置为mixed;


        //放到Message消息中
        mimeMessage.setContent(allFile);
        mimeMessage.saveChanges();//保存修改

        return mimeMessage;
    }
}

JavaWeb实现邮件发送:https://blog.csdn.net/qq_54897873/article/details/118557180

使用多线程,防止出现耗时,和网站注册人数过多的情况;

12、Maven

maven的常见问题,资源导出失败

	<!--在build中配置resources,防止资源导出失败的问题-->
	<resources>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>true</filtering>
      </resource>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>true</filtering>
      </resource>
    </resources>
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_50195602/article/details/125006637

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法