三十七、HTTP协议

HTTP 协议

什么是HTTP 协议

  • 协议是指双方,或多方,相互约定好,大家都需要遵守的规则,叫协议。
  • 所谓 HTTP 协议,就是指,客户端和服务器之间通信时,发送的数据,需要遵守的规则,叫HTTP 协议。
  • HTTP 协议中的数据又叫报文。

请求的HTTP 协议格式

  • 客户端给服务器发送数据叫请求。
  • 服务器给客户端回传数据叫响应。
  • 请求又分为 GET 请求,和 POST 请求两种

GET 请求与 POST 请求

  1. GET 请求
    1. 请求行
      1. 请求的方式 GET
      2. 请求的资源路径 [+?+请求参数]
      3. 请求的协议版本号 HTTP/1.1
    2. 请求头
      1. key : value 组成不同的键值对,表示不同的含义。
        http://localhost:8080/web01/hello?username=admin&password=123456

在这里插入图片描述

  1. POST 请求
    1. 请求行
      1. 请求的方式 POST
      2. 请求的资源路径 [+?+请求参数]
      3. 请求的协议版本号 HTTP/1.1
    2. 请求头
      1. key : value 不同的请求头,有不同的含义
    3. 请求体:就是发送给服务器的数据

发送 POST 请求:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
	<!-- /hello 前面的第一个 / 代表主机 localhost:8080-->
    <form action="/hello" method="post">
        用户名:<input type="text" name="username" id="username"><br/>

        密码:<input type="password" name="password" id="password"><br/>
        <input type="submit" value="提交">
    </form>
</body>
</html>
<?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">
<!--   注册servlet  -->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>cn.lanqiao.HelloServlet</servlet-class>
<!--        配置初始化时机,配置为0,则servlet随着容器的启动而完成构造和初始化-->
<!--        <load-on-startup></load-on-startup>-->
        <init-param>
            <param-name>username</param-name>
            <param-value>admin</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>12345</param-value>
        </init-param>
    </servlet>
<!--    配置servlet映射路径  -->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

在这里插入图片描述

如何区分 GET 请求与 POST 请求:

  • GET 请求:
    • form 标签method=get
    • a 标签
    • link 标签引入css
    • Script 标签引入js 文件
    • img 标签引入图片
    • iframe 引入html 页面
    • 在浏览器地址栏中输入地址后敲回车
  • POST 请求有哪些:
    • form 标签method=post

GET 请求与 POST 请求的区别

  • GET 会产生一个 TCP 数据包
    • 浏览器将 http header 与 date 一并发送出去
  • POST 会产生两个 TCP 数据包
    • 浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200
    • POST 时间消耗较多,但在验证数据包完整性方面有优点
    • 不是所有的浏览器都发送两次包

响应的 HTTP 协议格式

  1. 响应行
    (1) 响应的协议和版本号
    (2) 响应状态码
    (3) 响应状态描述符
  2. 响应头
    key : value 不同的响应头,有其不同含义
  3. 响应体: 就是回传给客户端的数据
  4. 常见的响应码说明:
    1. 200 表示请求成功
    2. 302 表示请求从定向
    3. 404 表示请求服务器已收到,但是所要的数据不存在(请求地址错误)
    4. 500 表示服务器已经收到请求,但是服务器内部错误(代码错误)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/app" method="post">
    用户名:<input type="text" name="username" id="username"><br/>
    密码:<input type="password" name="password" id="password"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>
<?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">
<!--   注册servlet  -->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>cn.lanqiao.HelloServlet</servlet-class>
<!--        配置初始化时机,配置为0,则servlet随着容器的启动而完成构造和初始化-->
<!--        <load-on-startup></load-on-startup>-->
        <init-param>
            <param-name>username</param-name>
            <param-value>admin</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>12345</param-value>
        </init-param>
    </servlet>
<!--    配置servlet映射路径  -->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>cn.lanqiao.AppServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/app</url-pattern>
    </servlet-mapping>
</web-app>
package cn.lanqiao;

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 AppServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost 执行");
        resp.sendRedirect("/success.html");
    }
}

在这里插入图片描述

MINE(content-type)类型说明

  • MINE 是 HTTP 协议中的数据类型

  • MINE(Multipurpose Internet Mail Extensions) 多功能Internet 邮件扩充服务。MIME 类型的格式是“大类型/小类型”,并与某一种文件的扩展名相对应。

  • 常见的 MINE 类型

文件MIME 类型
超文本标记语言文本.html , .htm text/html
普通文本.txt text/plain
RTF 文本.rtf application/rtf
GIF 图形.gif image/gif
JPEG 图形.jpeg,.jpg image/jpeg
au 声音文件.au audio/basic
MIDI 音乐文件mid,.midi audio/midi,audio/x-midi
RealAudio 音乐文件.ra, .ram audio/x-pn-realaudio
MPEG 文件.mpg,.mpeg video/mpeg
AVI 文件.avi video/x-msvideo
GZIP 文件.gz application/x-gzip
TAR 文件.tar application/x-tar

HttpServletRequest 类

作用

响应客户端

每次只要有请求进入Tomcat 服务器,Tomcat 服务器就会把请求过来的HTTP 协议信息解析好封装到Request 对象中。

然后传递到service 方法(doGet 和doPost)中给我们使用。我们可以通过HttpServletRequest 对象,获取到所有请求的信息。

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 AppServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求头的 accept 信息
        String accept = req.getHeader("Accept");
        System.out.println("accept = " + accept);
        //accept = text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
        // 获取请求的 URI 定位路径
        String uri = req.getRequestURI();
        System.out.println("uri = " + uri);  // uri = /app (主机之后的地址)

        // 获取请求的上下文路径,对于整个 web 应用而言,值是一致的,也可以看作请求的时候的项目的路径
        String contextPath = req.getContextPath();
        System.out.println("contextPath = " + contextPath);  // contextPath = 
        
        // 获取请求方式
        String method = req.getMethod();
        System.out.println("method = " + method);  // method = POST
        
        // 获取请求的网络地址
        String url = req.getRequestURL().toString();
        System.out.println("url = " + url);  // url = http://localhost:8080/app
        
        // 获取请求的 servlet 的 url-patern
        String servletPath = req.getServletPath();
        System.out.println("servletPath = " + servletPath);  // servletPath = /app
    }
}

通过 HttpServletRequest 获取请求的参数

通过地址栏获取(获取方式为 get):

Request URL: http://localhost:8080/app?username=admin&password=12345
Request Method: GET
public class AppServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过 req 获取请求参数,参数在传递的时候都是以键值对的形式存在的
        String username = req.getParameter("username");
        System.out.println("username = " + username);
        String password = req.getParameter("password");
        System.out.println("password = " + password);
        String sex = req.getParameter("sex");
        System.out.println("sex = " + sex);
        // 获取多个爱好信息
        String[] hobby = req.getParameterValues("hobby");
        for (String h : hobby){
            System.out.println("h = " + h);
        }
    }
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--只有表单能发送post请求-->
    <form action="/app" method="post">
        用户名:<input type="text" name="username" id="username"><br/>
        密码:<input type="password" name="password" id="password"><br/>
        性别:<input type="radio" name="sex" value="man"><input type="radio" name="sex" value="woman"><br>
        爱好:<input type="checkbox" name="hobby" value="bas">篮球
            <input type="checkbox" name="hobby" value="sc">足球
            <input type="checkbox" name="hobby" value="pp">乒乓球<br>
        <input type="submit" value="提交">
    </form>
</body>
</html>

在这里插入图片描述

username = amdin
password = admin
sex = woman
h = bas
h = sc
h = pp

当提交表单的时候,使用 req.getParameter 或者 req.getParameterValues 获取表单数据的时候,使用的是表单元素的 name 属性,因此在设计表单时,表单元素必须有 name 属性。

同时后台获取的数据都是其所对应的 values 属性的值。

通过 req.getParameter 或者 req.getParameterValues 得到的数据都是 String 类型

解决提交数据的中文乱码问题

GET 请求时,存在的中文乱码:

  • 解决方案一:先按照 UTF-8 解码,再使用 UTF-8 编码
String name = new String(username.getBytes(StandardCharsets.UTF_8),"UTF-8");
 String username =  req.getParameter("username");
 System.out.println("username = " + username);
 String name = new String(username.getBytes(StandardCharsets.UTF_8),"UTF-8");
 System.out.println("name = " + name);
  • 解决方案二:修改 tomcat 的 servlet.xml
    在这里插入图片描述

POST 请求的中文乱码:req.setCharacterEncoding(“UTF-8”); 必须写在所有获取参数之前

 @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   		// 解决通过 post 请求的中文乱码,必须写在获取参数之前
        req.setCharacterEncoding("UTF-8");
    }

HttpServletResponse

作用

HttpServletResponse 类和 HttpServletRequest 一样。每次请求,Tomcat 服务器都会创建一个Response 对象传递给Servlet 程序去使用。

HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,我们如果需要设置返回给客户端的信息,都可以通过HttpServletResponse 对象来进行设置

字节、字符输出流的说明

  • 字节流 getOutputStream() :常用于下载(传递二进制数据)
  • 字符流 getWriter() :常用于回传字符串(常用)

两种输出流只能同时使用一种。

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter out = resp.getWriter();
        out.write("username = " + username);
        out.write("password = " + "<h1>" + password + "<h1/>");
        out.write("sex = " + sex);
        out.flush(); // 刷新数据
    }

在网页上输出:

username = adminpassword = <h1>12345<h1/>sex = man

在这里插入图片描述

解决响应乱码问题(写在最前面):

  • 解决方法一:
resp.setContentType("text/html; charset=UTF-8");
  • 解决方法二(其实是方法一的分开形式):
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
  • 解决方法三:
resp.setHeader("Content-Type", "text/html; charset=UTF-8");

请求转发、重定向

  • 请求转发是指:服务器收到请求后,从一个资源跳转到另一个资源的操作
//将请求传递给另一个servlet来处理 请求转发
req.getRequestDispatcher("/demo").forward(req,resp);

req.getRequestDispatcher("/success.html").forward(req,resp);
  • 请求转发的特点:
    1. 地址栏的请求地址不变
    2. 请求转发只发送了一次请求
    3. 请求转发可以是 get 请求也可以是 post 请求
  • 请求转发的目标:
    1. 另一个 servlet
    2. 另一个 html 页面
  1. 请求转发若转发到 servlet ,此时两个 servlet 的 request 对象是同一个对象
  2. 因此可以在两个 servlet 中共享请求数据
  3. 请求转发只能转发到当前应用的内部资源

AppServlet 中请求转发:

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("APP Servlet 处理请求");
        // 将请求传递给另一个 servlet 来处理
        req.getRequestDispatcher("/demo").forward(req,resp);
    }
}

web.xml 中进行配置:

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demoServlet 处理请求");
    }
}

请求转发若转发到 servlet ,此时两个 servlet 的 request 对象是同一个对象 说明:

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demoServlet 处理请求");
        String username = req.getParameter("username");
        System.out.println("username = " + username);
        String password = req.getParameter("password");
        System.out.println("password = " + password);
    }
}

ServletDemo 中也可以获取到表单的数据

Web 中的相对路径与绝对路径

  • 相对路径是:
    • . 表示当前目录
    • … 表示上一级目录
    • 资源名 表示当前目录/资源名
  • 绝对路径:
    • http://ip:port/工程路径/资源路径
      在实际开发中,路径都使用绝对路径,而不简单的使用相对路径。

web 中 / 斜杠的不同意义:

  • 在web 中, / 是一种绝对路径
  • / 如果被服务器解析,得到的地址是: http://ip:post/
  • / 如果被服务器解析,得到的地址是:http://ip:port/工程路径
  • 特殊情况: response.sendRediect(“/”); 把斜杠发送给浏览器解析。得到http://ip:port/

base 的使用(只能在 jsp 文件中使用):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <base href="http://localhost:8080/">
</head>
<body>
<!--只有表单能发送post请求-->
    <form action="app" method="post">
        用户名:<input type="text" name="username" id="username"><br/>
        密码:<input type="password" name="password" id="password"><br/>
        性别:<input type="radio" name="sex" value="man"><input type="radio" name="sex" value="woman"><br>
        爱好:<input type="checkbox" name="hobby" value="bas">篮球
        <input type="checkbox" name="hobby" value="sc">足球
        <input type="checkbox" name="hobby" value="pp">乒乓球<br>
        <input type="submit" value="提交">
    </form>
</body>
</html>

重定向

重定向:将当前的请求重新定向到一个新的请求地址

请求重定向是指客户端给服务器发送请求,然后服务器告诉客户端说,我给你一些地址,你去新地址访问,叫请求重定向(之前的地址可能已经被废弃)

//重定向 地址是最终给到了浏览器
resp.sendRedirect("/web01/demo");
  1. 重定向的时候,地址栏的地址发生了变化,最终呈现的是重定向之后的请求地址
  2. 重定向发送了两次请求,第一次可以是 get 也可是post 但是第二次请求一定是 get 请求
  3. 因为是两次请求,所以 req 的数据无法共享
  4. 重定向不仅可以重定向到内部资源(例如转发到我们写的 success.html 页面),也可以重定向到外部资源。
// 重定向
// 重定向到内部资源
resp.sendRedirect("success.html");      
// 重定向到外部资源  resp.sendRedirect("http://www.baidu.com");
public class AppServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("APP Servlet 处理请求");
        // 将请求传递给另一个 servlet 来处理
        //req.getRequestDispatcher("/demo").forward(req,resp);
        // 重定向
        resp.sendRedirect("/demo");
    }
}

在这里插入图片描述

重定向共发起了两次请求

JavaEE 项目的三层架构

在这里插入图片描述
分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。

web 层com.web.web/servlet/controller
service 层com.web.service Service接口包
com.web.service.impl Service接口实现类
dao持久层com.web.dao Dao接口包
com.web.dao.impl Dao接口实现类
实体bean 对象com.web.pojo/entity/domain/beanJavaBean 类
测试包com.web.test/junit
工具类com.web.utils

创建工程引入静态资源

在这里插入图片描述
引入两个依赖:
tomcat目录中 lib中的 jsp-api.jar 和 servlet-api.jar

注:所有的 jar 包放在 WEB-INF 下

若还无法使用,再进行下述设置:

在这里插入图片描述

创建数据库及表

create table t_user(
id int primary key auto_increment,
username varchar(20) not null unique,
password varchar(32) not null,
email varchar(200)
);
insert into t_user(username,password,email) values(‘admin’,‘admin’,‘admin@126.com’);
select * from t_user;

编写数据库表对应的 JavaBean 对象

写一个 User 类

public class User {
    private Integer id;
    private String username;
    private String password;
    private String email;

    public User() {
    }

    public User(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }

    public User(Integer id, String username, String password, String email) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.email = email;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

链接数据库

导包(jdbc druid dbutils)

在这里插入图片描述

jdbc.properties

username=root
password=root
url=jdbc:mysql://localhost:3306/book
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10

JDBC 工具类

public class JDBCUtils {
    private static DruidDataSource dataSource;
    static {
        try {
            Properties properties = new Properties();
            // 读取jdbc.properties 属性配置文件
            InputStream inputStream =
                    JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
            // 从流中加载数据
            properties.load(inputStream);
            // 创建数据库连接池
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取数据库连接池中的连接
     * @return 如果返回null,说明获取连接失败<br/>有值就是获取连接成功
     */
    public static Connection getConnection(){
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
    /**
     * 关闭连接,放回数据库连接池
     * @param conn
     */
    public static void close(Connection conn){
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

基于 DBUtils 结合泛型,创建一个 BaseDao

public abstract class BaseDAO {
    //使用DbUtils 操作数据库
    private QueryRunner queryRunner = new QueryRunner();
    /**
     * update() 方法用来执行:Insert\Update\Delete 语句
     *
     * @return 如果返回-1,说明执行失败<br/>返回其他表示影响的行数
     */
    public int update(String sql, Object... args) {
        Connection connection = JDBCUtils.getConnection();
        try {
            return queryRunner.update(connection, sql, args);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(connection);
        }
        return -1;
    }
    /**
     * 查询返回一个javaBean 的sql 语句
     *
     * @param type 返回的对象类型
     * @param sql 执行的sql 语句
     * @param args sql 对应的参数值
     * @param <T> 返回的类型的泛型
     * @return
     */
    public <T> T queryForOne(Class<T> type, String sql, Object... args) {
        Connection con = JDBCUtils.getConnection();
        try {
            return queryRunner.query(con, sql, new BeanHandler<T>(type), args);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(con);
        }
        return null;
    }
    /**
     * 查询返回多个javaBean 的sql 语句
     *
     * @param type 返回的对象类型
     * @param sql 执行的sql 语句
     * @param args sql 对应的参数值
     * @param <T> 返回的类型的泛型
     * @return
     */
    public <T> List<T> queryForList(Class<T> type, String sql, Object... args) {
        Connection con = JDBCUtils.getConnection();
        try {
            return queryRunner.query(con, sql, new BeanListHandler<T>(type), args);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(con);
        }
        return null;
    }
    /**
     * 执行返回一行一列的sql 语句
     * @param sql 执行的sql 语句
     * @param args sql 对应的参数值
     * @return
     */
    public Object queryForSingleValue(String sql, Object... args){
        Connection conn = JDBCUtils.getConnection();
        try {
            return queryRunner.query(conn, sql, new ScalarHandler(), args);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(conn);
        }
        return null;
    }
}

创建 UserDao 并完成测试

public interface IUserDao {
    //新增用户 完成注册
    int  insert(User user);
    // 完成登陆  根据用户名和密码查询用户是否存在
    User selectUserByUsernameAndPassword(String username,String password);
    // 用户名唯一 在注册时候 检测用户名是否被占用
    User  selectUserByUser(String username);
}

实现接口:

public class UserDaoImpl extends BaseDAO implements IUserDao {
    @Override
    public int insert(User user) {
        String sql = "insert into t_user(username,password,email) values(?,?,?)";
        return  update(sql,user.getUsername(),user.getPassword(),user.getEmail());
    }

    @Override
    public User selectUserByUsernameAndPassword(String username, String password) {
        String sql = "select * from t_user where username=? and password=?";
        return queryForOne(User.class,sql,username,password);
    }

    @Override
    public User selectUserByUser(String username) {
        String sql = "select * from t_user where username=? ";
        return queryForOne(User.class,sql,username);
    }
}

测试:

public class UserDAOTest {
    private IUserDao userDao ;
    @BeforeEach
    public  void init(){
        userDao = new UserDaoImpl();
    }
    @Test
    public void insertTest(){
        User user = new User("tom","123466","tom@126.com");
        userDao.insert(user);
    }
    @Test
    public  void selectUserTest(){
      User user =   userDao.selectUserByUser("tom");
        System.out.println("user = " + user);
    }
}

Service 层

Service接口:

public interface IUserService {
    //保存用户
    int save(User user);
    //登陆
    User  login(String username,String password);
    //检查用户名是否被占用
    User checkUsername(String username);
}

Service 的实现:

public class UserService  implements IUserService {
    private IUserDao userDao = new UserDaoImpl();

    @Override
    public int save(User user) {

        return userDao.insert(user);
    }

    @Override
    public User login(String username, String password) {
        return userDao.selectUserByUsernameAndPassword(username,password);
    }

    @Override
    public User checkUsername(String username) {
        return userDao.selectUserByUser(username);
    }
}

Web 层

controller 是 servlet 处理浏览器发送的请求,并给出响应

public class LoginController  extends HttpServlet {
    private IUserService userService = new UserServiceImpl();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 接收用户输入的用户名和密码
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        User user = userService.login(username,password);
        System.out.println("user = " + user);
        if(user!=null){
            req.getRequestDispatcher("/pages/user/login_success.html").forward(req,resp);
        }else{
            resp.sendRedirect("/pages/user/login.html");
        }
    }

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

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">
    <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>cn.lanqiao.book.controller.LoginController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
</web-app>

Login.html

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>零点读书会员登录页面</title>
<link type="text/css" rel="stylesheet" href="../../static/css/style.css" >
<base href="http://localhost:8080/book/">
</head>
<body>
      <div id="login_header">
         
      </div>
      
         <div class="login_banner">
         
            <div id="l_content">
               <img class="login_img" alt="" src="../../static/img/logo.jpg" >
            </div>
            
            <div id="content">
               <div class="login_form">
                  <div class="login_box">
                     <div class="tit">
                        <h1>零点会员</h1>
                        <a href="regist.html">立即注册</a>
                     </div>
                     <div class="msg_cont">
                        <b></b>
                        <span class="errorMsg">请输入用户名和密码</span>
                     </div>
                     <div class="form">
                        <form action="login" method="post">
                           <label>用户名称:</label>
                           <input class="itxt" type="text" placeholder="请输入用户名" autocomplete="off" tabindex="1" name="username" />
                           <br />
                           <br />
                           <label>用户密码:</label>
                           <input class="itxt" type="password" placeholder="请输入密码" autocomplete="off" tabindex="1" name="password" />
                           <br />
                           <br />
                           <input type="submit" value="登录" id="sub_btn" />
                        </form>
                     </div>
                     
                  </div>
               </div>
            </div>
         </div>
      <div id="bottom">
         <span>
            零点读书.Copyright &copy;2020
         </span>
      </div>
</body>
</html>

注册

controller 文件

public class RegistController  extends HttpServlet {
    private IUserService userService = new UserServiceImpl();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username= req.getParameter("username");
        String password = req.getParameter("password");
        String email = req.getParameter("email");
        User user = new User(username,password,email);
        userService.save(user);
        req.getRequestDispatcher("/pages/user/regist_success.html").forward(req,resp);
    }
}

web.html 中添加:

<servlet>
    <servlet-name>regist</servlet-name>
    <servlet-class>cn.lanqiao.book.controller.RegistController</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>regist</servlet-name>
    <url-pattern>/regist</url-pattern>
</servlet-mapping>

注册页面(html 文件):

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>零点读书会员注册页面</title>
<base href="http://localhost:8080/book/">
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<style type="text/css">
   .login_form{
      height:420px;
      margin-top: 25px;
   }
   
</style>
<script type="text/javascript" src="../../static/js/jquery-1.12.4.js"></script>
<script type="text/javascript">
    // 页面加载完成之后
    $(function () {
        // 给注册绑定单击事件
        $("#sub_btn").click(function () {
            // 验证用户名: 必须由字母, 数字下划线组成, 并且长度为 5 到 12 位
            //1 获取用户名输入框里的内容
            var usernameText = $("#username").val();
            //2 创建正则表达式对象
            var usernamePatt = /^\w{5,12}$/;
            //3 使用 test 方法验证
            if (!usernamePatt.test(usernameText)) {
            //4 提示用户结果
            $("span.errorMsg").text("用户名不合法! ");
            return false;
            } 
            //验证密码: 必须由字母, 数字下划线组成, 并且长度为 5 到 12 位
            //1 获取用户名输入框里的内容
            var passwordText = $("#password").val();
            //2 创建正则表达式对象
            var passwordPatt = /^\w{5,12}$/;
            //3 使用 test 方法验证
            if (!passwordPatt.test(passwordText)) {
                //4 提示用户结果
                $("span.errorMsg").text("密码不合法! ");
                return false;
            } 
            //验证确认密码: 和密码相同
            //1 获取确认密码内容
            var repwdText = $("#repwd").val();
            //2 和密码相比较
            if (repwdText != passwordText) {
                //3 提示用户
                $("span.errorMsg").text("确认密码和密码不一致! ");
                return false;
            }
             //邮箱验证: xxxxx@xxx.com
            //1 获取邮箱里的内容
            var emailText = $("#email").val();
            //2 创建正则表达式对象
            var emailPatt = /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/;
            //3 使用 test 方法验证是否合法
            if (!emailPatt.test(emailText)) {
                //4 提示用户
                $("span.errorMsg").text("邮箱格式不合法! ");
                return false;
            } 
            //验证码: 现在只需要验证用户已输入。 因为还没讲到服务器。 验证码生成。
            var codeText = $("#code").val();
            //去掉验证码前后空格
            alert("去空格前: ["+codeText+"]")
            codeText = $.trim(codeText);
            alert("去空格后: ["+codeText+"]")
            if (codeText == null || codeText == "") {
                //4 提示用户
                $("span.errorMsg").text("验证码不能为空! ");
                return false;
            } 
            $("span.errorMsg").text("");
        });
    });
</script>

</head>
<body>
      <div id="login_header">
         <img class="login_img" alt="" src="static/img/logo.jpg" >
      </div>
      
         <div class="login_banner">
         
            <div id="l_content">
               <span class="login_word">欢迎注册</span>
            </div>
            
            <div id="content">
               <div class="login_form">
                  <div class="login_box">
                     <div class="tit">
                        <h1>注册零点读书会员</h1>
                        <span class="errorMsg"></span>
                     </div>
                     <div class="form">
                        <form action="regist" method="post">
                           <label>用户名称:</label>
                           <input class="itxt" type="text" placeholder="请输入用户名" autocomplete="off" tabindex="1" name="username" id="username" />
                           <br />
                           <br />
                           <label>用户密码:</label>
                           <input class="itxt" type="password" placeholder="请输入密码" autocomplete="off" tabindex="1" name="password" id="password" />
                           <br />
                           <br />
                           <label>确认密码:</label>
                           <input class="itxt" type="password" placeholder="确认密码" autocomplete="off" tabindex="1" name="repwd" id="repwd" />
                           <br />
                           <br />
                           <label>电子邮件:</label>
                           <input class="itxt" type="text" placeholder="请输入邮箱地址" autocomplete="off" tabindex="1" name="email" id="email" />
                           <br />
                           <br />
                           <label>验证码:</label>
                           <input class="itxt" type="text" style="width: 150px;" id="code"/>
                           <img alt="" src="static/img/code.bmp" style="float: right; margin-right: 40px">
                           <br />
                           <br />
                           <input type="submit" value="注册" id="sub_btn" />
                           
                        </form>
                     </div>
                     
                  </div>
               </div>
            </div>
         </div>
      <div id="bottom">
         <span>
            零点读书.Copyright &copy;2020
         </span>
      </div>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BORN(^-^)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值