JavaWeb

1、Maven

1.在javaweb开发中,需要使用大量的jar包

2.如何能够让一个东西帮我们导入和配置这个jar包

​ 由此,Maven诞生了

1.1 Maven项目架构管理工具

我们目前就是用来方便导入jar包的

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

  • 有约束,不要去违反

Maven会规定好你该如何去编写我们的java代码,必须按照这个规范来

1.2 下载安装Maven

https://maven.apache.org/download.cgi

image-20210818104908317

1.3配置环境变量

在我们的系统环境变量中

配置如下信息:

  • M2_HOME maven目录下的bin目录
  • MAVEN_HOME maven的目录
  • 在系统的path中配置 %MAVEN_HOME%\bin

测试maven是否安装成功:

image-20210818110713801

1.4 阿里云镜像

  • 镜像:Mirrors
    • 作用:加速下载
  • 国内建议使用阿里云镜像
<mirror>
        <id>alimaven</id>
        <mirrorOf>central</mirrorOf>
        <name>aliyun maven</name>
        <url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
    </mirror>

1.5 本地仓库

在本地的仓库、远程仓库;

建立一个本地仓库:localRepository

D:\Environment\apache-maven-3.8.2\maven-repo

1.6、在IDEA中使用Maven

  • 启动IDEA
  • 创建一个MavenWeb项目

image-20210818124523079

image-20210818125123501

  • IDEA自动下载一些东西

image-20210818125522050

  • 观察Maven仓库中的变化

  • IDEA中的Maven设置

IDEA中配置Maven,经常在IDEA中会出现一个问题:项目自动创建完成之后,它这个MavenHome会使用IDEA默认,如果发现了这个问题,需要手动修改为本地

image-20210818130234043

image-20210818131348483

1.7、创建一个普通的Maven项目

新建项目的时候不勾选使用maven模板

image-20210818131048440

1.8、标记文件夹功能

image-20210818132138691

image-20210818132238552

1.9、在IDEA中配置Tomcat

image-20210828170238077

解决警告问题

问题产生原因:我们访问一个网站,需要指定一个文件夹名字

image-20210828170401540

虚拟路径映射image-20210828170620004

image-20210828170941736

image-20210828171245819

1.10 POM文件

pom.xml 是Maven的核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!--Maven版本和头文件-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

<!--  这里就是配置的GAV-->
  <groupId>org.example</groupId>
  <artifactId>JavaWeb</artifactId>
  <version>1.0-SNAPSHOT</version>
<!-- package:项目的打包方式
 jar:java应用
 war:javaweb应用
 -->
  <packaging>war</packaging>

  <name>JavaWeb Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

<!--  配置-->
  <properties>
<!--    项目的默认构建编码-->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--    编码版本-->
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

<!--  项目依赖-->
  <dependencies>
<!--    具体依赖的jar包配置文件-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

<!--  项目构建用的东西-->
  <build>
    <finalName>JavaWeb</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

1.11 IDEA操作

image-20210828174547411

image-20210828174441979

2、Servlet

在客户端无法访问WEB-INF文件中的东西

2.1、Servlet简介

  • Servlet是sun公司开发动态web的一门技术
  • Sun在这些API中提供了一个接口,叫做Serlvet,如果想开发一个Serlvet程序,需要以下两个步骤:
    • 编写一个类,实现Serlvet接口
    • 把开发好的Java类部署到web服务器中

把实现了Serlvet接口的Java程序叫Serlvet

2.2、HelloSerlvet

Servlet接口在Sun公司有两个默认实现类:HttpServlet 、 GenericServlet

1.构建一个普通的Maven项目,删除掉里面的src目录,以后就在这个项目里面新建Moudel;这个空的工程就是Maven主工程

2.关于Maven父子工程的理解

父项目会有

<modules>
        <module>servlet-01</module>
</modules>

子项目会有

<parent>
        <artifactId>javaweb-02-serlvet</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

父项目中的java,子项目可以直接使用

son extends father

3.Maven环境优化

  • ​ 修改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>
  • 将maven的结构搭建完整

4.编写一个servlet程序

  • 编写一个普通类
  • 实现Servlet接口,这里我们可以直接继承HttpServlet
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //ServletOutputStream outputStream = resp.getOutputStream();/
        PrintWriter writer = resp.getWriter();//响应流
        writer.print("Hello,Servlet");
    }

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

image-20210829234359409

5.编写Servlet的映射

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

<!--注册Servlet-->
<servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.luo.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

6.配置Tomcat

​ 注意:配置项目发布的路径

7.启动测试

2.3、Servlet原理

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

image-20210830141532321

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

注意:/* 为默认通配符,会直接进如该项目,不会进入首页

  1. 指定一些后缀或者前缀等等

​ 可以自定义后缀实现请求映射,注意:*前面不能加项目映射的路径。使用*.adminluo ,可以通过/hello/test.adminluo进入该映射路径

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

5.优先级问题

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

实现自定义404:

web.xml:

<!--404-->
    <servlet>
        <servlet-name>error</servlet-name>
        <servlet-class>com.luo.servlet.ErrorServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>error</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

ErrorServlet:

package com.luo.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class ErrorServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");

        PrintWriter writer = resp.getWriter();
        writer.print("<h1>404</h1>");
    }

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

2.4、ServletContext

在web.xml中也可以设置context-param 【配置web应用初始化参数】

    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
    </context-param>
<!--
以键值对的方式设置参数url的值为jdbc:mysql://localhost:3306/mybatis
-->

1、共享数据

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

  • 共享数据

    我在这个Servlet中保存的数据,可以在另外一个servlet中拿到,以实现数据共享

    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">
    
    
        <servlet>
            <servlet-name>getc</servlet-name>
            <servlet-class>com.luo.servlet.GetServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>getc</servlet-name>
            <url-pattern>/getc</url-pattern>
        </servlet-mapping>
    
        <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.luo.servlet.HelloServlet</servlet-class>
    </servlet>
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
    </web-app>
    

    HelloServlet (设置所要共享的数据):

    package com.luo.servlet;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //this.getInitParameter() 初始化参数
            //this.getServletConfig() Servlet配置
            //this.getServletContext()  Servlet上下文
            ServletContext context = this.getServletContext();
            String username = "罗";
            context.setAttribute("username",username);//将一个数据保存在了ServletContext中,名字为username。值 username
    
            System.out.println("Hello");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    

    GetServlet (取得所要共享的数据):

    package com.luo.servlet;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class GetServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext context = this.getServletContext();
            String username = (String) context.getAttribute("username");
    
            resp.setContentType("text/html;charset=utf-8");
            resp.getWriter().print("名字:"+username);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    
    

    测试访问

2、获取初始化参数

  • 先设置初始化参数 【在web.xml中】

    <context-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
        </context-param>
    <!--
    以键值对的方式设置参数url的值为jdbc:mysql://localhost:3306/mybatis
    -->
    
  • 获取初始化参数

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

3、请求转发

image-20210831094431911

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("in demo04");
        ServletContext context = this.getServletContext();
        RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");  //转发的请求路径
        requestDispatcher.forward(req,resp);    //调用forward实现请求方法
    }

4、读取资源文件

Properties

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

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

public class ServletDemo05 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        InputStream is = this.getServletContext().getResourceAsStream("WEB-INF/classes/db.properties");
        Properties prop = new Properties();
        prop.load(is);
        String user = prop.getProperty("username");
        String passwd = prop.getProperty("password");

        resp.getWriter().print(user+":"+passwd);
        is.close();
    }

2.5、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 setContentType(String var1);

    void setBufferSize(int 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_CONTINUE = 100;
    int SC_SWITCHING_PROTOCOLS = 101;
    int SC_OK = 200;
    int SC_CREATED = 201;
    int SC_ACCEPTED = 202;
    int SC_NON_AUTHORITATIVE_INFORMATION = 203;
    int SC_NO_CONTENT = 204;
    int SC_RESET_CONTENT = 205;
    int SC_PARTIAL_CONTENT = 206;
    int SC_MULTIPLE_CHOICES = 300;
    int SC_MOVED_PERMANENTLY = 301;
    int SC_MOVED_TEMPORARILY = 302;
    int SC_FOUND = 302;
    int SC_SEE_OTHER = 303;
    int SC_NOT_MODIFIED = 304;
    int SC_USE_PROXY = 305;
    int SC_TEMPORARY_REDIRECT = 307;
    int SC_BAD_REQUEST = 400;
    int SC_UNAUTHORIZED = 401;
    int SC_PAYMENT_REQUIRED = 402;
    int SC_FORBIDDEN = 403;
    int SC_NOT_FOUND = 404;
    int SC_METHOD_NOT_ALLOWED = 405;
    int SC_NOT_ACCEPTABLE = 406;
    int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
    int SC_REQUEST_TIMEOUT = 408;
    int SC_CONFLICT = 409;
    int SC_GONE = 410;
    int SC_LENGTH_REQUIRED = 411;
    int SC_PRECONDITION_FAILED = 412;
    int SC_REQUEST_ENTITY_TOO_LARGE = 413;
    int SC_REQUEST_URI_TOO_LONG = 414;
    int SC_UNSUPPORTED_MEDIA_TYPE = 415;
    int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    int SC_EXPECTATION_FAILED = 417;
    int SC_INTERNAL_SERVER_ERROR = 500;
    int SC_NOT_IMPLEMENTED = 501;
    int SC_BAD_GATEWAY = 502;
    int SC_SERVICE_UNAVAILABLE = 503;
    int SC_GATEWAY_TIMEOUT = 504;
    int SC_HTTP_VERSION_NOT_SUPPORTED = 505;

2、下载文件

  1. 向浏览器输出消息

  2. 下载文件

    中文乱码问题:

    resp.setContenType("text/html");
    resp.setCharacterEncoding("utf-8");
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1. 要获取下载文件的路径
            String realPath = "D:\\JavaWeb\\javaweb-02-serlvet\\response\\src\\main\\resources\\1.png";
            System.out.println("下载的文件路径:"+realPath);
            //2. 下载的文件名
            String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
            //3. 设置想办法让浏览器能够支持下载我们需要的东西,中文文件名URLEncoder.encode编码,否则可能会产生乱码
            resp.setHeader("Contest-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. 将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区的数据输出到客户端
            while ((len = in.read(buffer))>0){
                out.write(buffer,0,len);
            }
            out.close();
            in.close();
        }
    
    1. 要获取下载文件的路径
    2. 下载的文件名
    3. 设置想办法让浏览器能够支持下载我们需要的东西
    4. 获取下载文件的输入流
    5. 创建缓冲区
    6. 获取OutputStream对象
    7. 将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区的数据输出到客户端
  3. 验证码功能

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

验证码实现代码:

package com.luo.servlet;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.Buffer;
import java.util.Random;

public class ImageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //让浏览器3秒自动刷新一次
        resp.setHeader("refresh","3");

        //在内存中创建一个图片
        BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
        //得到图片
        Graphics2D g =(Graphics2D) image.getGraphics(); //笔
        //设置图片的背景颜色
        g.setColor(Color.white);
        g.fillRect(0,0,70,20);
        //给图片写数据
        g.setColor(Color.BLUE);
        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());
    }

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

    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、实现重定向

image-20210901165306211

常见场景

  • 用户登录

       void sendRedirect(String var1) throws IOException;
    

    index.jsp:

    <html>
    <body>
    <h2>Hello World!</h2>
    <%@ page contentType="text/html; charset=UTF-8"%>
    <form action="${pageContext.request.contextPath}/login" method="get">
        用户名:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        <input type="submit" value="submit">
    </form>
    </body>
    </html>
    
    

    RequestTest.java:

    在web.xml中,指向该文件的路径为${pageContext.request.contextPath}/login 【即tomcat配置的路径/login】

    package com.luo.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class RequestTest extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("进入了这个请求");
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            System.out.println(username+":"+password);
            resp.sendRedirect("/response_war/success.jsp");
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    

    success.jsp:

    <%--
      Created by IntelliJ IDEA.
      User: AdminLuo
      Date: 2021/9/1
      Time: 17:26
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ page isELIgnored="false"%>
    <html>
    <head>
        <title>success</title>
    </head>
    <body>
    <h1>Success!</h1>
    </body>
    </html>
    
    

在body里面添加这个:<%@ page contentType="text/html; charset=UTF-8"%>

如果跳转失败证明jsp页面还不支持el表达式,最简单的方法是在jsp上面加上<%@ page isELIgnored="false"%>

jsp代码里面加上这些话<%@ page contentType="text/html; charset=UTF-8" %>

2.6、HttpServletRequest

1、获取前端传递的参数,并且请求转发

//以下两种用的较多
req.getParameter(String s)		String
req.getParameterValues(String s)   String[]

getRequestDispatcher分成两种,可以用request调用,也可以用getServletContext()调用

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

        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobby = req.getParameterValues("hobbys");
        System.out.println("===========================");
        //后台接收中文乱码问题
        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobby));
        System.out.println("============================");

        //System.out.println(req.getContextPath());
        //通过请求转发
        //这里的   /   代表当前web应用
        req.getRequestDispatcher("/success.jsp").forward(req,resp);
    }

重定向和转发的区别

相同点

  • 页面都会实现跳转

不同点

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

3、Cookie、Session

3.1、会话

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

两者的不同:

  1. 存储位置不同: cookie是保存在客户端, session是保存服务器端
  2. 存储数据量大小不同: cookie存储是有限的, 不超过4KB, seesion是无限制的;
  3. 存储的数据类型不同:cookie只能存储键值对的字符串类型,而session可以存储任意类型
  4. 默认有效期不同:cookie默认是会话级别的cookie,而session默认有效期是30分钟

3.2、保存会话的两种技术

Cookie

  • 客户端技术 响应,请求

Session

  • 服务器端技术,利用这个技术,可以保存用户的会话信息

Cookie

public class CookieDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

        PrintWriter out = resp.getWriter();

        //Cookie  服务器端从客户端获取
        Cookie[] cookies = req.getCookies();

        //判断cookie是否存在
        if(cookies != null){
            out.write("你上一次访问的时间是:");

            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                //获取cookie的名字
                if (cookie.getName().equals("lastLoginTime")){
                    //获取cookie中的值
                    long lastLoginTime = Long.parseLong(cookie.getValue());
                    Date date = new Date(lastLoginTime);
                    out.write(date.toLocaleString());
                }
            }

        }
        else {
            out.write("您这是第一次访问本站");
        }
        Cookie cookie = new Cookie("lastLoginTime",System.currentTimeMillis()+"");
        resp.addCookie(cookie);
        //服务器端从客户端获取Cookie


    }

out是jsp的内置对象

用name.equals能避免空指针异常

Session

image-20210902214340477

image-20210902214406723

demo03用来注销session,内容如下:【手动注销session】

image-20210902214422309

还可以在web.xml中设置session默认生效时间

其是以分钟为单位

image-20210902213515521

Session 和 Cookie的区别

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

Session是面向单个用户的,ApplicationContext/ServletContext是面向全体用户的,一个是你自己的储物柜,一个是大院子

3、JSP

Java Server Pages:Java服务器端页面,也和Servelt一样,用于动态web技术

最大的特点:

  • 写JSP就像在写HTML
  • 区别
    • HTML只给用户提供静态的数据
    • JSP页面中可以嵌入JAVA代码,为用户提供动态数据

3.2、JSP原理

JSP到底怎么执行的

IDEA TomCat的工作空间

image-20210905112348037

项目地址:

C:\Users\AdminLuo\AppData\Local\JetBrains\IntelliJIdea2021.2\tomcat\d378a619-ff6f-41d2-8537-467da81ee8df\work\Catalina\localhost\ROOT\org\apache\jsp

发现页面转变成了Java程序image-20210905112816879

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

JSP最终也会转换成为一个Java类

JSP本质上就是一个Servlet

//初始化
public void _jspInit() {
  }
//销毁
  public void _jspDestroy() {
  }
//JSPService
  public void _jspService(HttpServletRequest request, HttpServletResponse response)
  1. 判断请求

  2. 内置一些对象

        final javax.servlet.jsp.PageContext pageContext;  //页面上下文
        javax.servlet.http.HttpSession session = null;  //session
        final javax.servlet.ServletContext application;   //applicationContext
        final javax.servlet.ServletConfig config;    //config
        javax.servlet.jsp.JspWriter out = null;   //out
        final java.lang.Object page = this;
    //page:当前页
    HttpServletRequest request,//请求
    HttpServletResponse response//响应
    
  3. 输出页面钱增加的代码

    response.setContentType("text/html");
    pageContext = _jspxFactory.getPageContext(this, request, response,
                                              null, true, 8192, true);
    _jspx_page_context = pageContext;
    application = pageContext.getServletContext();
    config = pageContext.getServletConfig();
    session = pageContext.getSession();
    out = pageContext.getOut();
    _jspx_out = out;
    
  4. 以上的对象可以在JSP页面中直接使用image-20210905121143199

在JSP页面中,只要是JAVA代码就会原封不动的输出;

如果是HTML代码,就会被转发为:

out.write("<html>\r\n")

这种格式,输出到前端

3.3、JSP基础语法

JSP表达式

<%--JSP表达式
作用;用来将程序的输出,输出到客户端
<%= 变量表达式%>
--%>
<%= new java.util.Date()%>
还可以使用EL表达式:
${Java代码}

JSP脚本片段

  <%
  int sum = 0;
    for (int i = 1; i < 100; i++) {
      sum+=i;
    }
    out.println("<h1>sum="+sum+"</h1><p>test</p>");
  %>
<%
  for (int i = 0; i < 5; i++) {
%>
  <h1>helloworld <%=i%></h1>
  <%
    }
  %>

JSP声明

  <%!
  static {
    System.out.println("Loading Servlet");
  }
  private int globalVar = 0;
  public void test(){
    System.out.println("进入了方法test!");
  }
  %>

JSP声明:会被编译到JSP生成的Java类中,其他的会被生成到_jspService方法中

在JSP中嵌入Java代码中即可

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

3.4、JSP指令

格式:

<%@page args...%>
<%@include file=""%>

image-20210907235900635

↑↑↑↑直接访问500.jsp会找不到图片,同样是路径问题,这里可以改成${pageContext.request.contextPath}/img/500.png

也可以将img目录修改为resource目录

显式地声明这是一个错误页面

<%@ page isErrorPage="ture"%>

image-20210908000325669

3.5、九大内置对象

  • PageContext 保存东西
  • Request 保存东西
  • Response
  • Session 保存东西
  • Application 【ServletContext】 保存东西
  • config 【ServletConfig】
  • out
  • page , 几乎不用
  • exception 异常

脚本片段中的代码会被原封不动的生成到_jsp.java中,因此,在脚本片段中,注释符号需要使用//【必须保证java语法的正确性】

<%
    pageContext.setAttribute("name1","test1");
    request.setAttribute("name2","test2");
    session.setAttribute("name3","test3");
    application.setAttribute("name4","test4");
%>

<%
    //从pageContext取出,通过寻找的方式来进行
    //从底层到高层(作用域):page-->request-->session-->application
    //JVM:双亲委派机制 双亲委派机制是先找上级加载器,再找下级的,最上级没有才会从下级找
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");
    pageContext.setAttribute();
%>

<%--EL表达式取的是setAttribute()中的name1,没有findAttribute()也可以获取--%>
<%--转换成String的name是灰色的说明就没用上,只有<%=name>才用上--%>
<h1>取出的值为:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
<h3>${name5}</h3>
<%=name5%>
<%
    pageContext.setAttribute("hello","hello1",pageContext.SESSION_SCOPE);
    //上述代码与session.setAttribute("hello","hello1");等价
%>
<%
    pageContext.forward("/index.jsp");
    //以上代码与request.getRequestDispatcher("/index.php").forward(request,response); 等价
%>

如果EL表达式不生效,请在JSP页面最上面加上:<%@page isELIgnored="false" %>

双亲委派机制,遇到相同类名即向上加载,寻找优先级最高的包。即如果下层有与上层相同的包,则会使用最上层的包(优先级最高)

${}中取的是 上面存的 不是 String的 String那个是无效的

request:客户端向服务器发送请求,产生的数据,用户用完就没用了,比如新闻

session:客户端向服务器发送请求,产生的数据,用户用完一会了还有用,比如购物车

application:客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如聊天数据、统计网站在线人数

3.6、JSP标签、JSTL标签、EL表达式

使用JSTL标签需要导入jar包:

<dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>jstl-api</artifactId>
    <version>1.2</version>
</dependency>

JSP标签

image-20210909154344998

EL表达式: ${}

  • 获取数据
  • 执行运算
  • 获取web开发的常用对象

JSTL表达式

JSTL标签库的使用就是为了弥补HTML标签的不足,它自定义许多标签,可以供我们使用,标签的功能和Java代码一样

核心标签 (掌握部分即可)

image-20210912090512763

JSTL标签库使用步骤:

  • 引入对应的taglib
  • 使用其中的方法
  • 在Tomcat中也需要引入JSTL的包,否则会报错:JSTL解析错误
<body>

<%--定义一个变量score,值为85--%>
<c:set var="score" value="85"/>

<c:choose>
    <c:when test="${score}>=90">
        good
    </c:when>
    <c:when test="${score}>=80">
        just soso
    </c:when>
    <c:when test="${score}<60">
    bad!
    </c:when>
</c:choose>

</body>

image-20210912220254224

格式化标签

SQL标签

XML标签

4、JavaBean

实体类

JavaBean有特定的写法

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

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

ORM:对象关系映射

  • 表--->类
  • 字段--->属性
  • 行记录--->对象

people表

id name age address
1 admin1 3 湖南
2 admin2 18 湖南
3 admin3 24 湖南
class People{
    private int id;
    private String name;
    private int age;
    private String address;
}

class A{
    new People(1,"admin1",3,"湖南");
    new People(2,"admin2",18,"湖南");
    new People(3,"admin3",24,"湖南");

}

新建数据库、库中的表

image-20210914090920347

ajax请求

image-20210914093415649

5、MVC三层架构

Servlet和JSP都可以写Java代码,为了易于维护和使用,Servlet专注于处理i请求以及控制视图跳转【通过重定向或者转发】

JSP专注于显示数据

JAVA类要和数据库连接,需要通过JDBC

之前使用的:

image-20210914141108390

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

servlet-->CRUD(曾删改查)-->数据库
弊端:程序十分臃肿,不利于维护
Servlet的代码中,处理请求、响应、视图跳转、处理JDBC、处理业务代码、处理逻辑代码

架构:可以加一层来解决

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

Model:实体类和数据库中对应的一个个字段

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

View:JSP页面

  • 展示数据

  • 提供一些可以供我们操作的请求

  • 提供连接发起Servlet请求

Controller:控制器,即我们写的Servlet

  • 接收用户的请求
  • 响应给客户端内容
  • 重定向或者转发
登录--->接收用户的登录请求--->处理用户的请求(获取用户登录的参数,username,password)--->交给业务层处理登录业务(判断用户名密码是否正确)--->Dao层查询用户名和密码是否正确--->在数据库中进行查询

MVC三层架构

Dao层去操作数据库,实体类就是单独的了

实体类因为所有人都会用到(公共模块)

image-20210914155427192

6、Filter

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

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

过滤器需要实现过滤器接口

Filter开发步骤

  1. 导包

  2. 编写过滤器

    1. 导包的时候注意:需要导javax.servlet的Filter。否则没用image-20210915214201062

    2. 实现Filter接口,重写对应的方法

      package com.luo.filter;
      
      import javax.servlet.*;
      import java.io.IOException;
      
      public class CharEncodingFilter implements Filter {
          @Override
          //初始化   web服务器一启动就初始化了
          public void init(FilterConfig filterConfig) throws ServletException {
      
          }
      
          @Override
          public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
              /*
              * 1,过滤中的所有代码,在过滤特定请求的时候都会执行
              * 2. 必须要让过滤器继续通行:filterChain.doFilter(servletRequest,servletResponse);  【固定代码。不写的话,过滤器不会继续通行】
               */
              servletRequest.setCharacterEncoding("utf-8");
              servletResponse.setCharacterEncoding("utf-8");
              servletResponse.setContentType("text/html;charset=UTF-8");
      
              System.out.println("filter之前:");
              filterChain.doFilter(servletRequest,servletResponse);  //让我们的请求继续走,如果不写,程序执行到这里就会被拦截而不能继续往下执行。
              System.out.println("filter之后:");
          }
          //销毁
          @Override
          public void destroy() {
      
          }
      }
      
      
      1. 在web.xml中配置Filter过滤器
          <filter>
              <filter-name>charEncoding</filter-name>
              <filter-class>com.luo.filter.CharEncodingFilter</filter-class>
          </filter>
          <!--/servlet下的所有请求都会经过该过滤器-->
          <filter-mapping>
              <filter-name>charEncoding</filter-name>
              <url-pattern>/servlet/*</url-pattern>
          </filter-mapping>
      

7、监听器

实现一个监听器的接口;(有N种)

  1. 编写一个监听器

    实现监听器的接口,重写里面的方法

    package com.luo.listener;
    
    import javax.servlet.ServletContext;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    //统计网站在线人数
    
    //创建Session监听
    //一旦创建Session就会触发一次这个事件
    //HTTPSessionEvent 代表session时间对应的对象
    public class OnlineCountListener implements HttpSessionListener {
        @Override
        public void sessionCreated(HttpSessionEvent httpSessionEvent) {
            ServletContext ctx = httpSessionEvent.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
        //销毁sessio监听
        //一旦销毁session就会触发这个事件
        public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
            ServletContext ctx = httpSessionEvent.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);
        }
    }
    
    
  2. web.xml中注册监听器

        <listener>
            <listener-class>com.luo.listener.OnlineCountListener</listener-class>
        </listener>
    
  3. 注册完成之后,index.jsp页面:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
      <head>
        <title>$Title$</title>
      </head>
      request.getSession().getAttribute("OnlineCount")
      <body>
      <h1>当前有  <span><%=this.getServletConfig().getServletContext().getAttribute("OnlineCount")%></span>  人在线</h1>
      </body>
    </html>
    
    

首次打开页面,显示在线人不不为1的原因:tomcat在部署项目的时候,会启动该项目,生成少量session,因此不为一

需要重启tomcat时选择Redeploy,首次访问时才为1

image-20210915233335253

HTTPSessionEvent 代表session时间对应的对象

Session的销毁:

  • 手动:getSession().invalidate();
  • 自动:在web.xml中配置session-config 下的session-timeout

8、过滤器、监听器的常见使用

监听器:GUI编程中经常使用

package com.luo.listener;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class GuiListener {
    public static void main(String[] args) {
        Frame frame = new Frame("中秋节快乐");
        Panel panel = new Panel();
        frame.setLayout(null);

        frame.setBounds(300,300,500,500);  //设置frame的大小
        frame.setBackground(new Color(0,255,0));  //设置frame的背景颜色

        panel.setBounds(50,50,300,300);		//设置panel的大小
        panel.setBackground(new Color(0,0,255));   //设置panel的背景颜色

        frame.add(panel);   //将panel(小框)加入到frame中
        frame.setVisible(true);  //设置frame为可见的

        //监听事件,监听关闭事件
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("关闭中...");
                System.exit(0);
            }
        });

    }
}

exit(0) 和 exit(1) 的区别:一个是正常终止,一个是非正常终止

场景二:

用户登录后才能进入主页,用户注销后就不能进入

【使用过滤器可以实现】

如果转发的话,转发到/sys/success.jsp页面不能拿到数据,但是放到session中可以拿到数据

JDBC

什么是JDBC:Java连接数据库

image-20210923103520540

需要jar包的支持

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

实验环境搭建

数据库 表的创建

CREATE TABLE users(
	id INT PRIMARY KEY,
	`name` VARCHAR(40),
	`password` VARCHAR(40),
	email VARCHAR(60),
	birthday DATE
);

INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(1,'张三','123456','zs@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(2,'李四','123456','ls@qq.com','2000-01-01');
INSERT INTO users(id,`name`,`password`,email,birthday)
VALUES(3,'王五','123456','ww@qq.com','2000-01-01');

SELECT * FROM users;

1、导入数据库依赖

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

2、IDEA连接数据库

3、固定步骤

  1. 加载驱动
  2. 连接数据库,代表数据库
  3. 向数据库发送SQL的对象Statement,PrepareStatement:CRUD
  4. 编写SQL
  5. 执行查询SQL,返回一个ResultSet:结果集
  6. 关闭连接,释放资源 【先开后关】

增删改查:增删改都是使用executeUpdate

查询使用executeQuery

jdbc?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSl=true

最新的要在后面加上时区:serverTimezone=UTC

驱动是通过反射得到的 IDEA认为可能会找不到 所以要抛出异常

使用预编译

package com.luo.test;

import com.mysql.jdbc.Driver;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class TestJDBC2 {
    public static void main(String[] args) throws Exception{
        String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
        String username = "root";
        String password = "123456";

        Class.forName("com.mysql.jdbc.Driver");

        Connection connection = DriverManager.getConnection(url, username, password);

        String sql = "insert into users(id,name,password,email,birthday) values(?,?,?,?,?)";

        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        preparedStatement.setInt(1,4);
        preparedStatement.setString(2,"admin罗");
        preparedStatement.setString(3,"123456");
        preparedStatement.setString(4,"1297725225@qq.com");
        preparedStatement.setDate(5,new Date(new java.util.Date().getTime()));

        int i = preparedStatement.executeUpdate();

        if(i>0){
            System.out.println("insert success!");
        }

        preparedStatement.close();
        connection.close();


    }
}

事务

要么都成功,要么都失败

ACID原则:保证数据的安全

开启事务
事务提交 commit()
事务回滚 roolback()
关闭事务

转账:
    a:1000
    b:1000
    转账过程要么都成功,要么都失败

Junit(单元测试):写一个方法可以随时测试,不需要new或者main方法。

依赖:

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

image-20211025135705559

简单使用

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

随便写一个东西就可以测试

package com.luo.test;

import org.junit.jupiter.api.Test;

public class TestJDBC3 {
    @Test
    public void test(){
        System.out.println("hello");
    }
}

失败的时候是红色,报错

smbms服务搭建

image-20211110230220659

搭建一个环境

事务关闭自动提交默认开启事务

在java代码中:

通知数据库开启事务(flase为开启):

connection.setAutoCommit(false);

准备工作

db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql//localhost:3306?useUnicode=true&characterEncoding=utf-8
username=root
password=123456

编写DAO层:

package com.luo.dao;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class BaseDao {

    private static String driver;
    private static String url;
    private static String username;
    private static String password;

    static {
        //Properties类用来读取配置文件
        Properties properties = new Properties();
        InputStream is = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");

        try {
            properties.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }

        driver = properties.getProperty("driver");
        url = properties.getProperty("url");
        username = properties.getProperty("username");
        password = properties.getProperty("password");

    }
    //获取数据库的连接
    public static Connection getConnection(){
        //通过反射常见 Driver 对象.
        Connection connection = null;
        try {
            Class.forName(driver);
            connection = DriverManager.getConnection(url,username,password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connection;
    }

    //编写查询公共类的方法
    public static ResultSet execute(Connection connection, String sql, Object[] params, ResultSet resultSet, PreparedStatement preparedStatement) throws SQLException {
        //预编译sql,在后面直接执行就可以了
        preparedStatement = connection.prepareStatement(sql);

        for (int i = 0; i < params.length; i++) {
            //setObject,占位符从1开始,但是数组是从0开始
            preparedStatement.setObject(i+1,params[i]);

        }
        return resultSet;
    }

    //编写增删改公共方法
    public static int execute(Connection connection,String sql,Object[] params,PreparedStatement preparedStatement) throws SQLException {
        preparedStatement = connection.prepareStatement(sql);

        for (int i = 0; i < params.length; i++) {
            //setObject,占位符从1开始,但是数组是从0开始
            preparedStatement.setObject(i+1,params[i]);
        }
        int updateRows = preparedStatement.executeUpdate();
        return updateRows;
    }

    public static boolean closeResource(Connection connection,PreparedStatement preparedStatement,ResultSet resultSet){
        boolean flag = true;

        if(resultSet!=null){
            try {
                resultSet.close();
                //GC回收
                resultSet = null;
            } catch (SQLException e) {
                e.printStackTrace();
                flag = false;
            }
        }
        if(preparedStatement!=null){
            try {
                preparedStatement.close();
                //GC回收
                preparedStatement = null;
            } catch (SQLException e) {
                e.printStackTrace();
                flag = false;
            }
        }
        if(connection!=null){
            try {
                connection.close();
                //GC回收
                connection = null;
            } catch (SQLException e) {
                e.printStackTrace();
                flag = false;
            }
        }
        return flag;
    }

}

编写过滤器;

package com.luo.filter;

import javax.servlet.*;
import java.io.IOException;

public class CharacterEncodingFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");

        filterChain.doFilter(servletRequest,servletResponse);
    }

    public void destroy() {

    }
}

登录功能的实现

1.编写前端

2.设置首页

Dao层:持久化层

​ 面向接口编程

3.编写dao层登录用户的接口

package com.luo.dao.user;

import com.luo.pojo.User;

import java.sql.Connection;
import java.sql.SQLException;

public interface UserDao {

    //得到要登录的用户
    public User getLoginUser(Connection connection,String userCode) throws SQLException;
}

4.编写dao接口的实现类

package com.luo.dao.user;

import com.luo.dao.BaseDao;
import com.luo.pojo.User;
import com.mysql.jdbc.PreparedStatement;

import java.sql.Connection;
//import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 处理逻辑:
 * 从数据库中得到要登录的用户
 */
public class UserDaoImpl implements UserDao{

    public User getLoginUser(Connection connection, String userCode) throws SQLException {
        // ? 是为了保证安全,使用预编译sql

        PreparedStatement pstm = null;
        ResultSet rs = null;
        User user = null;

        if(connection!=null){
            String sql = "select * from smbms_user where userCode= ? ";

            Object[] params = {userCode};

            rs = BaseDao.execute(connection,pstm,rs,sql,params);
            //rs = BaseDao.execute(connection,pstm,rs,sql,params);
            //rs = BaseDao.execute(connection,pstm,rs,sql,params);
            if(rs.next()){
                user = new User();
                user.setId(rs.getInt("id"));
                user.setUserCode(rs.getString("userCode"));
                user.setUserName(rs.getString("userName"));
                user.setUserPassword(rs.getString("userPassword"));
                user.setGender(rs.getInt("gender"));
                user.setBirthday(rs.getDate("birthday"));
                user.setPhone(rs.getString("phone"));
                user.setAddress(rs.getString("address"));
                user.setUserRole(rs.getInt("userRole"));
                user.setCreateBy(rs.getInt("createdBy"));
                user.setCreationDate(rs.getTimestamp("creationDate"));
                user.setModifyBy(rs.getInt("modifyBy"));
                user.setModifyDate(rs.getTimestamp("modifyDate"));
            }
            BaseDao.closeResource(null,pstm,rs);

        }
    return user;

    }
}

5.业务层接口

UserService.java:

package com.luo.service.user;

import com.luo.pojo.User;

public interface UserService {
    //用户登录
    public User login(String usercode,String password);
}

6.业务层实现类

UserServiceImpl.java

package com.luo.service.user;

import com.luo.dao.BaseDao;
import com.luo.dao.user.UserDao;
import com.luo.dao.user.UserDaoImpl;
import com.luo.pojo.User;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.SQLException;

public class UserServiceImpl implements UserService {

    //业务层都会调用dao层,所以需要引入Dao层
    private UserDao userDao;
    public UserServiceImpl(){
        //构造函数,当实现UserServiceImpl的时候即自动实例化
         userDao = new UserDaoImpl();
    }

    public User login(String userCode, String password) {
        Connection connection = null;
        User user = null;

        try {
            connection = BaseDao.getConnection();
            //通过业务层调用具体的数据库操作
            user = userDao.getLoginUser(connection,userCode);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            BaseDao.closeResource(connection,null,null);
        }
        return user;
    }

    @Test
    public void test(){
        UserServiceImpl userService = new UserServiceImpl();
        User admin = userService.login("admin","1234567");
        System.out.println(admin.getUserPassword());
    }

}

7.编写servlet

package com.luo.servlet.user;

import com.luo.pojo.User;
import com.luo.service.user.UserService;
import com.luo.service.user.UserServiceImpl;
import com.luo.servlet.util.Constants;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("LoginServlet--start...");
        String userCode = req.getParameter("userCode");
        String userPassword = req.getParameter("userPassword");

        //和数据库中的密码进行对比,调用业务层
        UserService userService = new UserServiceImpl();
        User user = userService.login(userCode,userPassword);  //这里已经把登录的人查出来了

        if(user!= null){
            //将用户的信息放入session中
            req.getSession().setAttribute(Constants.USER_SESSION,user);
            //跳转到内部主页
            resp.sendRedirect("/jsp/frame.jsp");
        }
        else {//查不到该用户,无法登录
            //转发回登录页面,并提示用户名或者密码错误
            req.setAttribute("error","用户名或密码错误");
            req.getRequestDispatcher("login.jsp").forward(req,resp);
        }
    }

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

8.注册Servlet

    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.luo.servlet.user.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login.do</url-pattern>
    </servlet-mapping>

9.测试访问,确保以上功能成功

测试时出现报错:

Establishing SSL connetcion whitout server's identity verification is not recommended. 提示不安全的链接,则在db.properties文件中修改url为:useSSL=true

即:url=jdbc:mysql//localhost:3306?useSSL=true&useUnicode=true&characterEncoding=utf-8

登录功能优化

注销功能:

移除Session,返回登录界面

LogoutServlet:

package com.luo.servlet.user;

import com.luo.servlet.util.Constants;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LogoutServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //移除用户的Constants.USER_SESSION
        req.getSession().removeAttribute(Constants.USER_SESSION);
        resp.sendRedirect(req.getContextPath()+"/login.jsp");//返回登录页面
    }

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

登录拦截优化

SysFilter:

package com.luo.filter;

import com.luo.pojo.User;
import com.luo.servlet.util.Constants;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class SysFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        //过滤器,从session中获取用户
        User user = (User) request.getSession().getAttribute(Constants.USER_SESSION);

        if(user == null){
            response.sendRedirect("/smbms/error.jsp");
        }
        else{
            filterChain.doFilter(req,resp);
        }
    }

    public void destroy() {

    }
}

chain.dofilter作用是寻找下一个filter,但是user为null就没必要再寻找下一个filter过滤了所以写在false没问题

这里如果使用后退的话还是可以进去那个页面一下的,但是点击任何一个地方就会跳转到错误页面,一开始我还以为是我的过滤器不ok呢

密码修改

focus 聚焦

blur 失去焦点

三层架构,职责分离。需要修改就知道那一块出了问题

servlet层 获取参数,页面重定向

service层专注于处理业务,没有与数据库进行操作

1.导入前端素材

<li><a href="${pageContext.request.contextPath }/jsp/pwdmodify.jsp">密码修改</a></li>

2.写项目,建议从底层向上写

image-20211111123138441

3.UserDao接口

public int updatePwd(Connection connection,int id,int password) throws SQLException;

4.UserDao接口实现类

public int updatePwd(Connection connection, int id, int password) throws SQLException {
        PreparedStatement pstm = null;
        int execute = 0;
        if(connection != null){
            String sql = "update smbms_user set userPassword = ? where id = ?";
            Object params[] = {password,id};
            execute = BaseDao.execute(connection,pstm,sql,params);
            BaseDao.closeResource(null,pstm,null);
        }
        return execute;

    }

5.UserService层

//根据用户ID修改密码
public boolean updatePwd(int id,int pwd);

6.UserService实现类

    public boolean updatePwd(int id, int pwd) {
        Connection connection = null;
        boolean flag = false;

        try {
            connection = BaseDao.getConnection();
            if(userDao.updatePwd(connection,id,pwd)>0){
                flag = true;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            BaseDao.closeResource(connection,null,null);
        }
        return flag;
    }

7.实现复用。需要提取出方法

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("method");
        if (method != null && method.equals("savepwd")){
            this.updatePwd(req, resp);
        }
    }

8.测试

优化密码修改使用Ajax

Ajax 在页面没有刷新的情况下实现了交互

后台代码

    public void pwdmodify(HttpServletRequest req,HttpServletResponse resp){
        Object o = req.getSession().getAttribute(Constants.USER_SESSION);
        String oldpassword = req.getParameter("oldpassword");

        //万能的Map  :  结果集
        Map<String, String> resultMap = new HashMap<String, String>();
        if(o == null){//Session失效
            resultMap.put("result","error");
        }
        else if(StringUtils.isNullOrEmpty(oldpassword)){
            resultMap.put("result","error");
        }else{
            String userPassword = ((User) o).getUserPassword();
            if(oldpassword.equals(userPassword)){
                resultMap.put("result","true");
            }
            else{
                resultMap.put("result","false");
            }
        }

        try {
            resp.setContentType("application/json");//让上述方法返回一个JSON的值
//            resp.setContentType("text/html");
//            resp.setContentType("text/javascript");
            PrintWriter writer = resp.getWriter();
            writer.write(JSONArray.toJSONString(resultMap));
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

用户管理实现

image-20211114143503319

1.导入分页的工具类 (手写)

package com.luo.servlet.util;

public class PageSupport {
    //当前页码-来自用户输入
    private int currentPageNo = 1;

    //总数量  (表)
    private int totalCount = 0;

    //页面容量
    private int pageSize;

    //总页数-totalCount/pageSize (+1)
    private int totalPageCount;

    public int getCurrentPageNo(){
        return currentPageNo;
    }

    public void setCurrentPageNo(int currentPageNo){
        if(currentPageNo > 0){
            this.currentPageNo = currentPageNo;
        }
    }
    public int getTotalCount(){
        return totalCount;
    }
    public void setTotalCount(int totalCount){
        this.totalCount = totalCount;
        //设置总页数
        this.setTotalPageCountByRs();
    }
    public int getPageSize(){
        return pageSize;
    }

    public void setPageSize(int pageSize){
        if(pageSize > 0){
            this.pageSize = pageSize;
        }
    }

    public int getTotalPageCount(){
        return totalPageCount;
    }

    public void setTotalPageCount(int totalPageCount){
        this.totalPageCount = totalPageCount;
    }

    public void setTotalPageCountByRs(){
        if(this.totalCount % this.pageSize ==0){
            this.totalPageCount = this.totalCount / this.pageSize;
        }
        else if(this.totalCount % this.pageSize > 0){
            this.totalPageCount = this.totalCount / this.pageSize + 1;
        }
        else {
            this.totalPageCount = 0;
        }
    }
}

2.用户列表页面导入

userlist.jsp

获取用户数量

image-20211114225938308

image-20211114225942126

image-20211114225934161

1.UserDao

public List<User> getUserList(Connection connection,String userName,int userRole,int currentPageNo,int pageSize) throws Exception;

2.UserDaoImpl

    public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws Exception {
        //TODO Auto-generated method stub
        PreparedStatement pstm = null;
        ResultSet rs = null;
        List<User> userList = new ArrayList<User>();
        if(connection != null){
            StringBuffer sql = new StringBuffer();
            sql.append("select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r where u.userRole = r.id");
            List<Object> list = new ArrayList<Object>();
            if(!StringUtils.isNullOrEmpty(userName)){
                sql.append(" and u.userName like ?");
                list.add("%"+userName+"%");
            }
            if(userRole > 0){
                sql.append(" and u.userRole = ?");
                list.add(userRole);
            }
            sql.append(" order by creationDate DESC limit ?,?");
            currentPageNo = (currentPageNo-1)*pageSize;
            list.add(currentPageNo);
            list.add(pageSize);

            Object[] params = list.toArray();
            System.out.println("sql ----->" + sql.toString());
            rs = BaseDao.execute(connection,pstm,rs,sql.toString(),params);
            while (rs.next()){
                User _user = new User();
                _user.setId(rs.getInt("id"));
                _user.setUserCode(rs.getString("userCode"));
                _user.setUserName(rs.getString("userName"));
                _user.setGender(rs.getInt("gender"));
                _user.setBirthday(rs.getDate("birthday"));
                _user.setPhone(rs.getString("phone"));
                _user.setUserRole(rs.getInt("userRole"));
                _user.setUserRoleName(rs.getString("userRoleName"));
                userList.add(_user);
            }
            BaseDao.closeResource(null,pstm,rs);
        }
        return userList;
    }
}

3.UserService

    //根据条件查询用户列表
    public List<User> getUserList(String queryUserName,int queryUserRole,int currentPageNo,int pageSize);

4.UserServiceImpl

    public List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo, int pageSize) {
        Connection connection = null;
        List<User> userList = null;
        System.out.println("queryUserName --->" + queryUserName);
        System.out.println("queryUserRole --->" + queryUserRole);
        System.out.println("currentPageNo --->" + currentPageNo);
        System.out.println("pageSize --->" + pageSize);


        try {
            userList = userDao.getUserList(connection,queryUserName,queryUserRole,currentPageNo,pageSize);
            connection = BaseDao.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(connection,null,null);
        }
        return userList;
    }

获取角色操作

为了职责统一,可以把角色的操作单独存放在一个包中。和POJO类对应

RoleDao

public interface RoleDao {
    //获取角色列表
    public List<Role> getRoleList(Connection connection) throws SQLException;
}

RoleDaoImpl

package com.luo.dao.role;

import com.luo.dao.BaseDao;
import com.luo.pojo.Role;
import com.mysql.jdbc.PreparedStatement;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class RoleDaoImpl implements RoleDao{

    //获取角色列表
    public List<Role> getRoleList(Connection connection) throws SQLException {
        PreparedStatement pstm = null;
        ResultSet resultSet = null;
        ArrayList<Role> roleList = new ArrayList<Role>();
        if(connection != null){
            String sql = "select * from smbms_role";
            Object[] params = {};
            resultSet = BaseDao.execute(connection,pstm,resultSet,sql,params);

            //读取所有角色,放入一个列表中
            while(resultSet.next()){
                Role _role = new Role();
                _role.setId(resultSet.getInt("id"));
                _role.setRoleCode(resultSet.getString("roleCode"));
                _role.setRoleName(resultSet.getString("roleCode"));
                roleList.add(_role);
            }
            BaseDao.closeResource(null,pstm,resultSet);
        }
        return roleList;
    }

}

RoleService

package com.luo.service.role;

import com.luo.pojo.Role;

import java.util.List;

public interface RoleService {
    //获取角色列表
    public List<Role> getRoleList();
}

RoleServiceImpl

package com.luo.service.role;

import com.luo.dao.BaseDao;
import com.luo.dao.role.RoleDao;
import com.luo.dao.role.RoleDaoImpl;
import com.luo.pojo.Role;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public class RoleServiceImpl implements RoleService{

    //引入Dao
    private RoleDao roleDao;
    public RoleServiceImpl(){
        roleDao = new RoleDaoImpl();
    }
    public List<Role> getRoleList() {

        Connection connection = null;
        List<Role> roleList = null;
        try {
            connection = BaseDao.getConnection();
            roleList = roleDao.getRoleList(connection);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            BaseDao.closeResource(connection,null,null);
        }
        return roleList;
    }
}

image-20211115204317850

image-20211115204310003

image-20211115210106540

4、用户显示的Servlet

1.获取用户前端的数据

2.判断请求是否需要执行,看参数的值判断

3.为了实现分页,需要计算出当前页面和总页面,页面大小

4.用户列表展示

5.返回前端

文件上传

调优:

  1. 为了保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如WEB-INF目录下。
  2. 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名 【uuid 随机生成数、md5 、 位运算算法】
  3. 要限制文件上传的最大值
  4. 可以限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法

WEB-INF目录无法直接访问,只能通过重定向来进行间接访问

image-20211116110927128

Java虚拟机底层是用C++写的

Java不能操作本地方法,因为Java的一些都是操作在JVM上

JNI = Java Native Interface

Java无法操作计算机 , 因为有一层

不同的操作系统都有一个统一的JVM

posted @   admin_luo  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示