狂神web

1.Maven

1.1在IDEA中使用Maven

  1. 启动IDEA
  2. 创建一个MavenWeb项目

image.png
image.png
image.png
image.png
image.png
image.png

  1. 等待项目初始化完毕

image.png
image.png

  1. 观察maven仓库中多了什么东西?

  2. IDEA中的Maven设置

    注意:IDEA项目创建成功后,看一眼maven的配置![image.png](https://img-blog.csdnimg.cn/img_convert/a7629a9d03a890c2230cca82975aeb98.png)
    

1.2 创建一个普通的maven项目image.png

image.png
image.png
image.png
这个只有在web应用下才会有:
image.png

1.3 在IDEA中标记文件夹功能

image.png
image.png
image.png
image.png

1.4 在IDEA中配置Tomcat

image.png
image.png
image.png
解决警告问题
必须要的配置:为什么会有这个问题:我们访问一个网站,需要指定一个文件夹的名字;
image.png
image.png
image.png
image.png

1.5 pom文件

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

2.Servlet

2.1 servlet简介

  • Servlet就是sun公司开发动态web的一门技术

  • Sun在这些API中提供一个接口叫做:Servlet, 如果你想开发一个servlet程序,只需要完成两个小步骤:

        1. 编写一个类,实现servlet接口。
        2. 把开发好的java类部署到web服务器中。
    

把实现了servlet接口的java程序叫做: Servlet

2.2 HelloServlet

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

  1. 构建一个普通的Maven项目,删掉里面的src目录,以后我们的学习就在这个项目里面建立module,这个空工程就是maven的主工程。

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

    父项目中会有
    
<modules>
  <module>servlet</module>
</modules>
  子目录中会有
<parent>
        <artifactId>javaweb-02-servlet</artifactId>
        <groupId>com.kuang</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

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

2.3 Maven环境优化

  1.修改web.xml为最新的
  2.将Maven的结构搭建完整

2.4 编写一个Servlet程序

    1.编写一个普通类
    2. 实现servlet接口,这里我们直接继承HttpServlet
package com.kuang.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 HelloServlet extends HttpServlet {

     //由于get或者post只是请求实现的不同方式,可以相互调用,业务逻辑都一样

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      //
        PrintWriter writer = resp.getWriter();
        writer.print("hello servlet");

    }

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


    }
}

2.5 编写Servlet的映射

    为什么需要映射: 我们写的是java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务器中注册我们写的Servlet,还需要给他一个浏览器能够访问的路径;
<!--注册Servlet-->
<servlet>
  <servlet-name>hello</servlet-name>
  <servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
  <servlet-name>hello</servlet-name>
  <url-pattern>/hello</url-pattern>
</servlet-mapping>

2.6 配置Tomcat

     注意:配置项目发布的路径就可以了

2.7 启动测试, OK!

3. Servlet运行原理

servlet由web服务器调用,web服务器在收到浏览器请求之后,会:
image.png
image.png

4 . Mapping 问题

  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>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello3</url-pattern>
</servlet-mapping>
<servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello4</url-pattern>
</servlet-mapping>
  1. 一个Servlet可以指定通用映射路径
 <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello/*</url-pattern>
 </servlet-mapping>
  1. 默认请求路径
<!-- 默认路径 -->
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/*<url-pattern>
</servlet-mapping>
  1. 指定一些后缀或者前缀等等…
<!-- 可以自定义后缀实现请求映射
     注意点: *前面不能加项目映射的路径
      hello/sajdlkajda.qinqiang
-->
<servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>*.qinqiang</url-pattern>
<servlet-mapping>
  1. 优先级问题

    指定了固有的映射路径优先级最高(精确匹配),如果找不到就会走默认的处理请求;

5、ServletContext

web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用; (这个对象在整个应用程序的生命周期内保持不变。每个Web应用程序都有一个唯一的 ServletContext 对象,可以通过 Servlet API 中的 getServletContext() 方法来访问)

5.1 共享数据

     我在这个servlet中保存的数据,可以在另外一个servlet中拿到;
public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("hello");


        //this.getInitParameter()  : 初始化参数
        //this.getServletConfig()  : Servlet配置
        //this.getServletContext()   : Servlet上下文
        ServletContext context = this.getServletContext();

        String username = "秦疆";
        context.setAttribute("username",username); //将一个数据保存在了ServletContext中,名字为:username,值为“”

    }
}
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");
        resp.setCharacterEncoding("utf-8");

        resp.getWriter().print("名字" + username);
    }

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

    }
}
  <servlet>
         <servlet-name>hello</servlet-name>
         <servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
     </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>getc</servlet-name>
        <servlet-class>com.kuang.servlet.GetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>getc</servlet-name>
        <url-pattern>/getc</url-pattern>
    </servlet-mapping>

测试访问结果;

5.2 获取初始化参数

  • 设置参数
<!--配置一些web应用初始化参数-->
    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
    </context-param>
  • 使用ServletContext对象获取初始化参数值
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        String url = context.getInitParameter("url");
        resp.getWriter().print(url);
    }
  • 在web.xml配置中改servlet
   <servlet>
        <servlet-name>gp</servlet-name>
        <servlet-class>com.kuang.servlet.ServletDemo03</servlet-class>
    </servlet>

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

5.3 请求转发

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

        ServletContext context = this.getServletContext();
        System.out.println("进入了ServletDemo04");
//        RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");
//        requestDispatcher.forward(req, resp);
        context.getRequestDispatcher("/gp").forward(req, resp);
    }

image.png

5.4 读取资源文件

Properties类

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

发现:都被打包到了同一个路径下:classes,我们俗称这个路径为classpath:
思路: 需要一个文件流

username=root
password=12345
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 properties = new Properties();
        properties.load(is);
        String user = properties.getProperty("username");
        String pwd = properties.getProperty("password");

        resp.getWriter().print(user +":" + pwd);
    }

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

    <servlet>
        <servlet-name>sd5</servlet-name>
        <servlet-class>com.kuang.servlet.ServletDemo05</servlet-class>
    </servlet>

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

访问测试即OK;

6 . HtttpServletResponse

 web服务器收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse对象;
  • 如果要获取客户端请求过来的参数:找HttpServletRequest;

    HttpServletRequest是ServletRequest的子接口,它提供了用于处理HTTP请求的方法和属性,包括访问请求参数、请求头、会话信息等。在JSP中,request对象可以直接使用,而且通常用于从客户端接收数据、处理表单提交等HTTP相关的任务。所以,request对象提供了更多的HTTP请求相关功能,而不仅仅是ServletRequest的通用功能。
    
  • 如果要给客户端响应一些信息:找HttpServletResponse;

     HttpServletResponse是ServletResponse的子接口,它提供了用于处理HTTP响应的方法和属性,包括设置响应的内容类型、响应头、状态码等。在JSP中,你可以使用response对象来向客户端发送HTTP响应,包括HTML内容、重定向、设置响应头等操作。所以,response对象提供了更多与HTTP响应相关的功能,而不仅仅是ServletResponse的通用功能。
    

6.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 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;

6.2 常见应用

1.向浏览器输出消息
2.下载文件
1.要获取下载文件的路径
2.下载的文件名是啥?
3.设置想办法让浏览器能够支持下载我们需要的东西
4.获取下载文件的输入流
5.创建缓冲区
6.获取OutputStream对象
7.将FileOutputStream流写入到buffer缓冲区
8.使用OutputStream将缓冲区中的数据输出到客户端!

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 //1.要获取下载文件的路径
    String realPath = " D:\\CodeWarehouse\\maven_code\\javaweb-02-servlet\\response\\target\\classes\\1.jpg";
    System.out.println("获取到的路径为:" + realPath);
    //2.下载的文件名
    String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
    System.out.println(fileName);

    //3.设置让浏览器能够支持(Content-disposition)下载我们需要的东西
    resp.setHeader("Content-disposition","attachment;filename"+fileName);

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

    //5.创建缓冲区
    int len = 0;
    byte[] buffer = new byte[1024];

    //6.获取OutputStream对象
    //ServletOutputStream类提供一个输出流用于向客户端发送二进制数据
    ServletOutputStream out = resp.getOutputStream();
    FileInputStream in = new FileInputStream(realPath);

    //7.将FileOutputStream流写入到buffer缓冲区
    while ((len = in.read(buffer)) > 0){
        out.write(buffer, 0, len);
    }

    //8.
    in.close();
    out.close();

}

3.实现重定向
image.png
一个web资源B收到客户端A的请求后,他会通知客户端A去访问另一个web资源C,这个过程叫重定向。
常见场景:

  • 用户登录
    void sendRedirect(String var1) throws IOException;

面试题:请求转发和重定向的区别:
相同点:

  • 页面都会实现跳转

不同点:

  • 请求转发的时候,url不会产生变化 307
  • 重定向的时候,url地址栏会发生变化; 302
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html lang = "en">
<head>
  <meta charset=UTF-8">
</head>
<body>

<form action="${pageContext.request.contextPath}/login" method="get">
  用户名: <input type="text" name="username"> <br>
  密码:   <input type="password" name="password"> <br>
  <input type="submit">
</form>
</body>
</html>

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

        //处理请求
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        
        //重定向时候一定要注意路径问题
        resp.sendRedirect("/success.jsp");

        System.out.println(username + ": " + password);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doGet(req, resp);
    }
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<h2>Success</h2>

</body>
</html>

7.HttpServletRequest

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

注:HttpServletRequest的对象就是JSP的九大内置对象中的request。
image.png
image.png

7.1 获取前端传递的参数

image.png
重点是第一个(返回类型为字符串)和第四个(返回类型为字符数组)。

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

        req.setCharacterEncoding("UTF-8");

        String username = req.getParameter("username");   //使用的是方法一
        String password = req.getParameter("password");
        String[] hobbys = req.getParameterValues("hobbys");  //使用的是方法四
        System.out.println("=============================================");
        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobbys ));
        System.out.println("=============================================");

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

    }

7.2 请求转发

8 . Cookie、Session

8.1 会话

会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话。
有状态会话:
你能怎么证明你是南师大的学生?
你 南师大

  1. 校园卡 南师大给你发放的校园卡
  2. 学校教务系统登记 南师大的教务系统数据库中记录有你的信息

一个网站,怎么证明你来过?
客户端 服务器
1.服务端给客户端一个信件,客户端下次访问服务器带上信件就可以了: cookie
2.服务端登记你来过了,下次你来的时候我来匹配你;session

8.2 保存会话的两种技术

cookie

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

session

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

常见技术:网站登录后,你下次不用再登录了,第二次访问直接就登录上了!

8.3 Cookie

image.png

  1. 从请求中拿到cookie信息。
  2. 服务器响应给客户端cookie。
Cookie[] cookies = req.getCookies();           //获得cookie
cookie.getName();           //获得cookie中的key
cookie.getValue();          //获取cookie中的value
new Cookie("lastLoginTime", System.currentTimeMills()+"");      //新建一个cookie
cookie.setMaxAge(24 * 60 * 60);     //设置cookie的有效期
resp.addCookie(cookie);    //响应给客户端一个cookie

cookie一般保存在本地的用户目录下 appdata;
一个网站cookie是否存在上限?

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

如何删除cookie?

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

问题:Cookie是在服务端产生并发送(响应)给客户端(浏览器)的,那么为什么getCookie的操作是HttpServletRequest的对象完成的,而不是由HttpServletResponse的对象完成的?
答:HttpServletRequest对象代表从客户端(浏览器)发送到服务器的HTTP请求,它包含了请求的信息,例如请求的URL、请求的参数、请求的头部等等。当客户端发送HTTP请求时,浏览器会在请求头中附带之前保存的Cookie信息,这些Cookie会通过HttpServletRequest对象的方法来获取。
一旦Cookie被发送到客户端(浏览器),之后的请求都会自动带上该Cookie信息。当客户端发送新的HTTP请求时,浏览器会自动在请求头中带上之前保存的Cookie,这不需要开发者手动干预。
因此,HttpServletRequest对象提供了方法来获取客户端发送的Cookie信息,例如getCookies()方法,这样开发者就可以从中获取客户端浏览器携带的Cookie信息,并做相应的处理。
相比之下,HttpServletResponse对象主要用于向客户端(浏览器)发送HTTP响应。开发者可以使用
HttpServletResponse
对象设置响应头、响应内容以及发送Cookie等。
总结起来,获取Cookie的操作在HttpServletRequest对象完成是因为Cookie是由客户端发送到服务器的,而获取Cookie就是从客户端请求中获取信息。而设置Cookie的操作通常是通过HttpServletResponse对象来完成,因为要把Cookie发送给客户端浏览器保存。

package com.kuang.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

//保存用户上一次访问的时间
public class CookieDemo01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //服务器告诉你你来的时间,把这个时间封装成为一个信件, 你下次访问的时候带来,服务器就知道你来过了

        //解决中文乱码问题
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");

        PrintWriter out = resp.getWriter();            //PrintWriter是个打印流,属于字符输出流

        Cookie[] cookies = req.getCookies();      //返回的是数值,说明Cookie可能存在多个

        //判断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);     //创建指定毫秒数的Date对象
                    out.write(date.toLocaleString());
                }
            }
        }else{
            out.write("这是您第一次访问本站");
        }
        //服务器给客户端响应一个cookie;
        Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
        resp.addCookie(cookie);
    }

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

8.4 Session(重点)

image.png
什么是Session?

  • 服务器会给每一个用户(浏览器)创建一个Session对象
  • 一个Session独占一个浏览器,只要浏览器没有关闭,这个Session就存在;
  • 用户登录之后,整个网站它都可以访问! —>保存用户的信息;保存购物车的信息…

Session和Cookie的区别:
image.png
Session和cookie的区别:

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

使用场景:

  • 保存一个登录用户的信息;
  • 购物车信息;
  • 在整个网站中经常会使用的数据,我们将它保存在session中。
package com.kuang.servlet;

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

public class SessionDemo03 extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取Session
        HttpSession session = req.getSession();
        session.removeAttribute("name");  //从session删除指定名称的绑定对象
        session.invalidate();  //这里注销后sessionId就没了,但是它会立马生成一个新的。

    }

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

会话自动过期: web.xml配置

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

销毁session,removeAttribute()和invalidate()的区别
image.png
疑问?
image.png
image.png

问题1: 为什么cookie需要生成,而session不用生成就存在了?
Cookie和Session都是在Web开发中用来管理用户状态的技术,但它们的工作原理略有不同。
Cookie: Cookie是存储在用户浏览器中的小文本文件,由服务器通过HTTP响应头发送给浏览器,然后浏览器将其保存下来。服务器可以在响应中设置一个或多个Cookie,这些Cookie可以包含一些数据,比如用户的身份信息、偏好设置等。当用户再次访问同一个网站时,浏览器会通过HTTP请求头将之前保存的Cookie发送回服务器。这样服务器就可以根据Cookie中的信息识别用户,并根据需要进行响应。
Session: Session是服务器端的一种机制,用于在服务器上存储用户状态信息。当用户第一次访问网站时,服务器会为该用户创建一个唯一的Session ID,并将相关的用户信息存储在服务器的内存或数据库中。然后,服务器会将这个Session ID 发送给浏览器,通常是通过Cookie的形式。随后,用户每次请求都会携带这个Session ID。服务器根据Session ID 来查找存储在服务器上的用户信息,从而实现用户状态的管理。
所以,虽然Session不需要显式地生成,但实际上服务器会在用户第一次访问时自动创建Session,并将Session ID 传递给客户端,从而实现后续的状态管理。而Cookie是用来存储在客户端的数据,需要服务器主动设置并发送给浏览器。两者在实现用户状态管理时都起到了重要的作用,但机制略有不同。
问题2:cookie是由谁创建的,session又是怎么来的呢?
image.png
tip:Servlet和HTTP请求之间的关系是,Servlet是用来处理HTTP请求的,它们紧密联系,使得服务器能够根据客户端请求执行相应的业务逻辑。

9 . JSP

9.1 什么是JSP

Java Server Pages : Java服务端页面,也和Servlet一样,用于动态Web技术!
最大的特点:

  • 写JSP就像在写HTML

  • 区别:

          HTML只给用户提供静态的数据
          JSP页面中可以嵌套Java代码,为用户提供动态数据;   
    

9.2 JSP原理

思路:JSP到底怎么执行的!

  • 代码层面没有任何问题

  • 服务器内部工作

        tomcat中有一个work目录;
        IDEA中使用Tomcat的话,会在IDEA的tomcat中生成一个work目录(IDEA的空间在C盘)![image.png](https://img-blog.csdnimg.cn/img_convert/682bebbd1e099a07509c9ba3d5eb1abf.png)
    

在本机上的地址:

C:\Users\14205\.IntelliJIdea2017.2\system\tomcat\Unnamed_javaweb-session-cookie_2\
    work\Catalina\localhost\ROOT\org\apache\jsp

发现页面转变成了java程序!
image.png
浏览器向服务器发送请求,不管访问什么资源,其实都是在访问Servlet!
JSP最终也会被替换成一个java类!
JSP本质上就是一个Servlet!

//初始化
public void _jspInit() {
}
//
public void _jspDestroy() {
}
//JSPService
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.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                       //响应
exception
  1. 输出页面前增加的代码
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;
  1. 以上的这些对象我们可以在JSP页面中直接使用!

image.png
在JSP页面中;
只要是JAVA代码就会原封不动的输出;
如果是HTML代码,就会被转换为:

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

这样的格式,输出到前端!
附:index_jsp.java代码如下:

// index_jsp.java
/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/8.0.33
 * Generated at: 2023-08-11 10:53:14 UTC
 * Note: The last modified time of this file was set to
 *       the last modified time of the source file after
 *       generation to assist with modification tracking.
 */
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  private volatile javax.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
        throws java.io.IOException, javax.servlet.ServletException {

final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}

    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;


    try {
      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;

      out.write("<html>\n");
      out.write("<body>\n");
      out.write("<h2>Hello World!</h2>\n");
      out.write("</body>\n");
      out.write("</html>\n");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

9.3 JSP基础语法

任何语言都有自己的语法,java中有,JSP作为java技术的一种应用,它拥有一些自己扩充的语法(了解,知道即可!),java所有语法都支持!

JSP表达式

<%--JSP表达式
作用: 用来将程序的输出,输出到客户端
<%= 变量或者表达式%>
--%>
<%= new java.util.Date()%>

jsp脚本片段

<%--jsp脚本片段--%>
<%
int sum = 0;
for(int i = 0; i < 100; i++){
sum += i;
}
out.println("<h1>sum=" + sum + "<h1>");
%>

脚本片段的再实现

<%
int x = 10;
out.println(x);
%>
<p>这是一个JSP文档</p>
<%
int y = 20;
out.println(y);
%>

<%--在代码中嵌入HTML元素--%>
<%
for (int i = 0; i < 5; i++) {
%>
<h1>Hello, World ! <%= i %></h1>
<%
 }
%>

JSP声明

<%!
   static{
     System.out.println("Loading Servlet!");
   }

   private int globalVar = 0;

   public void kuang(){
     System.out.println("进入了方法kuang!");
   }
%>

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

在JSP中,嵌入java代码即可!

<%%>    : 中写脚本程序(我的理解就是java代码)
<%=%>   : 中写表达式(变量或表达式)
<%!%>   : JSP声明的语法格式

<%--注释-->

JSP的注释,不会在客户端显示; 但HTML的注释会!

补充:不使用模板方式创建web项目eg:
image.png
image.png
image.png
image.png
image.png

9.4 JSP指令

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

<%-- "/"代表当前项目(即web项目,web这个文件夹)--%>
<%--@include会将两个页面合二为一--%>
<%@include file="common/header.jsp"%>
<h1>网页主体</h1>
<%@include file="common/footer.jsp"%>

<hr>

<%--jsp标签--%>
<%--jsp:include: 拼接页面,本质上还是三个 --%>
<jsp:include page="/common/header.jsp"/>
<h1>网页主体</h1>
<jsp:include page="/common/footer.jsp"/>    

9.5 九大内置对象

  • PageContext : 页面上下文
  • Request : 请求
  • Response : 响应
  • Session : 会话
  • Application [ServletContext] : 存东西
  • config [ServletConfig]
  • page : 当前页
  • out :
  • exception :
pageContext.setAttribute("name1", "凯旋①号");  //保存的数据只在一个页面中有效
request.setAttribute("name2", "凯旋②号");     //保存的数据只在一次请求中有效,请求转发会携带这个数据
session.setAttribute("name3", "凯旋③号");     //保存的数据只在一次会话中有效,从打开浏览器到关闭浏览器
application.setAttribute("name4", "凯旋④号");  //保存的数据在服务器中有效,从打开服务器到关闭服务器

request : 客户端向服务器发送请求,产生的数据,用户看完就没用了,比如: 新闻, 用户看完没用的!
session: 客户端向服务器发送请求,产生的数据,用户用完一会儿还有用,比如: 购物车;
application: 客户端向服务器发送请求,产生的数据,一个用户用完了,其他用户还可能使用,比如: 聊天数据;

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

<!--jstl标签库-->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl-api -->
<dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>jstl-api</artifactId>
    <version>1.2</version>
</dependency>
<!--standard标签库-->
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>

EL表达式作用:

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

JSP标签

<%--jsp:include--%>
<%--http://localhost:8080/jsptag.jsp?name=kuangshen&age=12
--%>

<jsp:forward page="/jsptag2.jsp">
    <jsp:param name="name" value="kuangshen"></jsp:param>
    <jsp:param name="age" value="3"></jsp:param>
</jsp:forward>

JSTL表达式
JSTL标签库的使用就是为了弥补HTML标签的不足;它自定义了许多标签,可以供我们使用,标签的功能和java代码一样!
核心标签(掌握部分)
image.png
JSTL标签库使用步骤:

  • 引入对用的taglib
  • 使用其中的方法
  • 在Tomcat中也需要引入jstl的包,否则会报jstl解析错误

C:\Users\14205.m2\repository\javax\servlet\jsp\jstl\jstl-api\1.2
coreif、 corewhen、 coreforeach的例子如下:
coreif:


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入JSTL核心标签库,我们才能使用JSTL标签core--%>
<%@taglib prefix="c" uri = "http://java.sun.com/jsp/jstl/core"%>

<html>

<head>
    <title>Title</title>
</head>
<body>

<h4>if测试</h4>

<hr>
<form action="coreif.jsp" method="get">
    <%--
    EL表达式获取表单中的数据
    ${param.参数名}
    --%>
    <input type="text" name="username" value="${param.username}">
    <input type="submit" value="登录">


    <%--判断如果提交的用户名是管理员,则登录成功--%>
    <c:if test="${param.username=='admin'}" var="isAdmin"> <br/>
       <c:out value="管理员欢迎您!"/>
    </c:if>

</form>

<%--这是个自闭和标签--%>
<c:out value="${isAdmin}"/>

</body>
</html>

corewhen:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%--定义一个变量score,值为85--%>
<c:set var="score" value="85"/>
<c:choose>
    <c:when test="${score >= 90}">
         你的成绩为优秀!
    </c:when>
    <c:when test="${score >= 80}">
        你的成绩为良好!
    </c:when>
    <c:when test="${score >= 70}">
        你的成绩为一般!
    </c:when>
    <c:when test="${score <= 60}">
        你的成绩为不及格!
    </c:when>
</c:choose>

</body>
</html>

coreforeach:

<%@ page import="java.util.ArrayList" %>
<%--在 jsp 标签库中使用 taglib 指令引入标签库--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>Title</title>
</head>
<body>


<%--
var: 每一次遍历出来的变量
items: 要遍历的对象
begin: 哪里开始
end: 到哪里
step: 步长
--%>


<%
    ArrayList<String> people = new ArrayList<>();
    people.add("润泽");
    people.add("大冰");
    people.add("凯旋");
    people.add("爱萍");
    people.add("小婉");

    request.setAttribute("list", people);
%>

<c:forEach var="people" items="${list}">
    <c:out value="${people}"/> <br/>
</c:forEach>

<hr>

<c:forEach  var="people" items="${list}" begin="1" end="3" step="1">
    <c:out value="${people}"/> <br/>
</c:forEach>


</body>
</html>

10 . JavaBean

实体类
JavaBean有特定的写法:

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

一般用来和数据库的字段做映射 ORM;
ORM:对象映射关系

  • 表——> 类
  • 字段——>属性
  • 元组——>对象
    | id | name | age | address |
    | — | — | — | — |
    | 1 | 凯旋①号 | 17 | 临汾 |
    | 2 | 凯旋②号 | 16 | 太原 |
    | 3 | 凯旋③号 | 18 | 南京 |
class People{
   private int id; 
   private String name;
   private int age;
   private String address;
}

class A{
   new People(1, "凯旋①号", 17, "临汾");
   new People(2, "凯旋②号", 16, "太原");
   new People(3, "凯旋③号", 18, "南京");
}

11 . MVC三层架构

什么是MVC: Model View Controller 模型、视图、控制器
image.png
用户直接访问控制层,控制层就可以直接操作数据库;

servlet——> CRUD ——> 数据库
弊端: 程序十分臃肿,不利于维护     
servlet的代码中: 处理请求、响应、试图跳转、处理JDBC、处理业务代码、处理逻辑代码

架构:没有什么是加一层解决不了的!

11.2 MVC三层架构

image.png
Model:

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

View:

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

Controller:

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

12 . Filter

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

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

image.png
Filter开发步骤:

  1. 导包

  2. 编写过滤器

    1.导包不要导错
    image.png
    2.实现Filter接口,重写对应的方法即可

public class CharacterEncodingFilter implements Filter {

    //初始化:web服务器启动,就已经初始化了,随时等待过滤器对象出现!
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("CharacterEncodingFilter初始化");
    }

    //chain: 链
    /*
    * 1.过滤器中的所有代码,在过滤特定请求的时候都会执行
    * 2.必须要让过滤器继续通行
    *    chain.doFilter(request, response);
    * */
    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");

        System.out.println("CharacterEncodingFilter执行前....");
        chain.doFilter(request,response);  //固定的代码(让程序继续往下走的)
        System.out.println("CharacterEncodingFilter执行后....");

    }

    //销毁:web服务器关闭的时候,过滤会销毁
    public void destroy() {
        System.out.println("CharacterEncodingFilter销毁");
    }
}

3.在web.xml中配置Filter
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.kuang.filter.CharacterEncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!--只要是/servlet的任何请求,会经过这个过滤器-->
        <url-pattern>/servlet/*</url-pattern>
    </filter-mapping>

pom.xml文件

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

    <groupId>com.kuang</groupId>
    <artifactId>javaweb-filter</artifactId>
    <version>1.0-SNAPSHOT</version>

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

        <!--JSP依赖-->
        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
            <scope>provided</scope>
        </dependency>

        <!--JSTL表达式的依赖-->
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>jstl-api</artifactId>
            <version>1.2</version>
        </dependency>

        <!--standard标签-->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>

        <!--mysql驱动-->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>



    </dependencies>

</project>

13、监听器

实现一个监听器的接口; (有n种)
1.编写一个监听器
实现监听器的接口…

public class OnlineCountListener implements HttpSessionListener {
    //创建session监听
    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);
    }


    //销毁session监听
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {

    }
}
  1. web.xml中注册监听器
<!--注册监听器-->
    <listener>
        <listener-class>com.kuang.listener.OnlineCountListener</listener-class>
    </listener>

3.看情况是否使用!

14、过滤器、监听器常见应用

image.png

SMBMS

image.png
数据库
image.png
项目如何搭建?
考虑使不使用Maven ? 找依赖 : 导jar包

项目搭建:

  1. 搭建一个maven web项目

  2. 配置tomcat

  3. 测试项目是否能够跑起来

  4. 导入项目中会遇到的jar包

    servlet、jsp、mysql驱动,jstl、standard

  5. 创建包结构;

image.png

  1. 编写实体类;

    ORM映射: 表—类 映射
    image.png
    image.png
    image.png
    image.png

  2. 编写基础公共类

    1. 数据库配置文件(resources目录下写文件就可以了)
    
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306?useUnicode=true&characterEncoding=utf-8
username=root
password=672836466
  2.编写数据库的公共类
//BaseDao文件
package com.kuang.dao;

import com.mysql.fabric.xmlrpc.base.Param;

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 = 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() {

        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[] param, ResultSet resultSet,PreparedStatement preparedStatement ) throws SQLException {
        preparedStatement = connection.prepareStatement(sql);  //存在的异常:sql语句可能是无效的

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

        resultSet = preparedStatement.executeQuery();
        return resultSet;
    }


    //编写增删改公共方法
    public static int execute(Connection connection, String sql, Object[] param, PreparedStatement preparedStatement) throws SQLException {
        preparedStatement = connection.prepareStatement(sql);  //存在的异常:sql语句可能是无效的

        for (int i = 0; i < param.length; i++) {
            //setObject, 占位符从1开始, 但是我们的数组是从0开始的!
            preparedStatement.setObject(i+1, param[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();
                resultSet = null;
            } catch (SQLException e) {
                e.printStackTrace();
                flag = false;
            }
        }

        if (preparedStatement != null){
            try {
                preparedStatement.close();
                preparedStatement = null;
            } catch (SQLException e) {
                e.printStackTrace();
                flag = false;
            }
        }

        if (connection != null){
            try {
                connection.close();
                connection = null;
            } catch (SQLException e) {
                e.printStackTrace();
                flag = false;
            }
        }

        return flag;
    }

}

  3.编写字符编码过滤器
  1. 导入静态资源

image.png
image.png

登录功能实现

image.png
1.编写前端页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
  <html>
    <head lang="en">
      <meta charset="UTF-8">
      <title>系统登录-超市订单管理系统</title>
      <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath}/statics/css/style.css">
      <script>

      </script>
    </head>
    <body class="login_bg">
      <section class="loginBox">
        <header class="loginHeader">
          <h1>超市订单管理系统</h1>
        </header>
        <section class="loginCont">
          <form class="loginForm" action="${pageContext.request.contextPath}/login.do" name="actionForm" id="actionForm" method="post">
            <div class="info">${error}</div>
            <div class="inputbox">
              <label>用户名:</label>
              <input type="text" class="input-text" id="userCode" name="userCode" placeholder="请输入用户名" required/>
            </div>
            <div class="inputbox">
              <label>密码:</label>
              <input type="password" id="userPassword" name="userPassword" placeholder="请输入密码" required/>
            </div>
            <div class="subBtn">
              <input type="submit" value="登录"/>
              <input type="reset" value="重置"/>
            </div>
          </form>
        </section>
      </section>
    </body>
  </html>

2.设置首页

  <!--设置欢迎页面-->
    <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>

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

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

}

4.编写Dao层接口的实现类

public class UserDaoImpl implements UserDao{

    public User getLoginUser(Connection connection, String userCode) throws SQLException{

        PreparedStatement pstm = null;
        ResultSet rs = null;
        User user = new User();

        if(connection != null){
             String sql = "select * from smbms_user where userCode=?";
             //创建一个对象数组
             Object[] params = {userCode};
             rs = BaseDao.execute(connection, sql, params, rs, pstm);  //到这一步已经拿到结果集了,即已经执行了sql语句了。

             //处理得到的结果集
            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.setCreatedBy(rs.getInt("createdBy"));
                user.setCreationDate(rs.getTimestamp("creationDate"));
                user.setModifyBy(rs.getInt("modifyBy"));
                user.setModifyDate(rs.getTimestamp("modifyDate"));
            }
           BaseDao.closeResource(null, pstm, rs);  //connection可能存在业务,需要到事务层调业务的时候再去关闭。
        }

        return  user;
    }
}
  1. 业务层接口
public interface UserService {
    //用户登录
    public User login(String userCode, String password);

}
  1. 业务层实现
public class UserServiceImpl implements UserService{

    //业务层都会调用dao层,所以我们要引入Dao层。
    private UserDao userDao;
    public UserServiceImpl(){

    }

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

7.编写Servlet

package com.kuang.servlet.user;

import com.kuang.pojo.User;
import com.kuang.service.user.UserServiceImpl;
import com.kuang.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{
    //Servlet: 控制层,调用业务层代码

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

        System.out.println("LoginServlet--strat");

        //获取用户名和密码
        String userCode = req.getParameter("userCode");
        String userPassword = req.getParameter("userPassword");

        //和数据库中的密码进行对比,调用业务层;
        UserServiceImpl userService = new UserServiceImpl(); //创建UserServiceImpl对象的时候(调用空参的构造方法)就
                                                             //自动创建出了一个UserDaoImpl对象名为userDao
        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);
    }
}

  1. 注册servlet
 <!--注册Servlet-->
    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.kuang.servlet.user.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login.do</url-pattern>      //前端form表单中指定了发送到哪里
    </servlet-mapping>

image.png

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

登录功能优化

注销功能:
思路:移除Session, 返回登录页面

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("/login.jsp");

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
 <!--登录优化-->
    <servlet>
        <servlet-name>LogoutServlet</servlet-name>
        <servlet-class>com.kuang.servlet.user.LogoutServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LogoutServlet</servlet-name>
        <url-pattern>/logout.do</url-pattern>
    </servlet-mapping>

有关session的知识点回顾:

为什么ServletRequest对象获取不到Session, 而HttpServletRequest对象可以获取到session?
答:ServletRequest是一个更通用的接口,它表示了一个Http请求。这个接口并没有直接提供获取会话的方法。(如果只使用ServetRequest, 需要将其强制转换为HttpServletRequest才能访问会话。)

ServletRequest request = request;
HttpSession session = ((HttpServletRequest) request).getSession();

两个接口之间的关系:
‘HttpServletRequest’ 继承自’ServletRequest’, 它是一个专门用于处理HTTP请求的接口。 ‘HttpServletRequest’ 直接提供了获取会话的方法,如’getSession() ', 因此可以直接通过’HttpServletRequest’对象来获取会话。

HttpServletRequest request = request;
HttpSession session = request.getSession();

JavaEE规范Servlet和jdbc的区别:
image.png

登录拦截优化

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

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        //首先获取session(HttpServletRequest对象才能拿到session)
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

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

        if (user == null){   //如果user为空,就说明已经被移除或者是注销了,或者未登录。
            response.sendRedirect("/error.jsp");
        }else{
            chain.doFilter(req, resp);
        }
    }

    @Override
    public void destroy() {

    }
}

<!--登录拦截优化-->
    <filter>
        <filter-name>SysFilter</filter-name>
        <filter-class>com.kuang.filter.SysFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>SysFilter</filter-name>
        <url-pattern>/jsp/*</url-pattern>
    </filter-mapping>

密码修改

1.导入前端素材

<li><a href="${pageContext.request.contextPath }/jsp/pwdmodify.jsp">密码修改</a></li>
  1. 写项目,建议从底层往上写

image.png

  1. UserDao接口
public int updatePwd(Connection connection, int id, String password) throws SQLException;
  1. UserDao实现类
//修改当前用户密码
@Override
    public int updatePwd(Connection connection, int id, String password) throws SQLException {
    PreparedStatement preparedStatement = null;
    int execute = 0;
    if (connection != null) {
        String sql = "update smbms_user set userPassword = ? where id = ?";
        Object params[] = {password, id};
        execute = BaseDao.execute(connection, sql, params, preparedStatement);
        BaseDao.closeResource(null, preparedStatement, null);
    }
    return execute;
}

5.UserService接口

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

6.UserService实现类

@Override
public boolean updatePwd(int id, String pwd) {
    Connection connection = null;
    boolean flag = false;
    //修改密码
    try {
        connection = BaseDao.getConnection();
        if (userDao.updatePwd(connection, id, pwd) > 0){   //此处有sql异常
            flag = true;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        //关流
        BaseDao.closeResource(connection, null, null);
    }

    return flag;
}
  1. UserServlet实现类
public class LoginServlet extends HttpServlet{
    //Servlet: 控制层,调用业务层代码
    @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");

        //和数据库中的密码进行对比,调用业务层;
        UserServiceImpl userService = new UserServiceImpl(); //创建UserServiceImpl对象的时候(调用空参的构造方法)就
        //自动创建出了一个UserDaoImpl对象名为userDao
        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);
        }
    }

7.记得实现复用(Servlet复用),需要提取出方法!

package com.kuang.servlet.user;

import com.kuang.pojo.User;
import com.kuang.service.user.UserServiceImpl;
import com.kuang.util.Constants;
import com.mysql.jdbc.StringUtils;

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 UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("method");
        if(method.equals("savepwd") && method != null ){
            this.updatePwd(req, resp);
        }

    }

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

    public void updatePwd(HttpServletRequest req, HttpServletResponse resp){
        //从session里面拿id
        Object o = req.getSession().getAttribute(Constants.USER_SESSION);
        //获取前端传递的参数:新密码,因为是做修改密码的操作,所以要拿到前端输入的新密码去替换数据库中的旧密码。
        String newpassword = req.getParameter("newpassword");
        boolean flag = false;
        if (o != null && !StringUtils.isNullOrEmpty(newpassword)){
            //调用service层
            UserServiceImpl userService = new UserServiceImpl();
            flag = userService.updatePwd(((User) o).getId(), newpassword);
            if (flag){
                req.setAttribute("message", "密码修改成功,退出请使用新密码登录");
                //密码修改成功你,移除当前Session
                req.getSession().removeAttribute(Constants.USER_SESSION);

            }else{
                req.setAttribute("message", "密码修改失败");

            }
        }else{
            req.setAttribute("message", "新密码有问题");
        }
        //请求转发
        try {
            req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
  1. 测试

优化密码修改使用Ajax

  1. 阿里巴巴的fastjson
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.61</version>
</dependency>
  1. 后台代码修改

image.png

image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值