JavaWeb的学习总结1——(基本的servlet+JDBC)

403 阅读9分钟

一,目标

1,理解JavaEE的框架层级;

2,实现基本的前端+servlet+JDBC的功能;

3,熟练下各个层级代码的书写规范;

4,重点是在后端;

5,熟练掌握Druid连接池和DBUtils工具类库的使用;

二,框架层级分析

总的来说是不同层之间分工明确,但是不同层需要调用其他层的功能来处理本层的功能,利用组合的方式。使用类与类之间组合的方式使得框架的几层结构连接成一个整体。

  1. 先写了数据库连接池的JDBCUtils,实现java代码建立一个数据库连接池,并且可以随时从连接池中获取到连接和关闭connection对象,从而可以操作数据库。
  2. 定义了Dao持久层的规范,DAO:Data Access Object访问数据库信息的类和接口,包括了对数据(一般是JavaBean对象)的CRUD(Create、Retrival、Update、Delete),而不包含任何业务相关的信息。有时也称作:BaseDAO。作用:为了实现功能的模块化,更有利于代码的维护和升级。

BaseDao抽象类:包括了对数据(一般是JavaBean对象)的CRUD(Create、Retrival、Update、Delete),具有复用性,不对具体业务。一般使用DBUtils工具类库。

UserDao接口:具体的某个JavaBean类的接口,接口内定义的抽象方法都是具体的JavaBean对象需要的业务功能,比如xxx。

UserDaoImpl类:继承BaseDao抽象类,可以调用通用的BaseDao抽象类的方法,实现UserDao接口,实现UserDao接口中业务的方法。

上述属于从数据库到Dao层,实现了Dao层得到的数据写入到数据库中,并能够从数据库中得到指定的数据回传到Dao层进行验证。

  1. 然后是Service业务层,这一层处理从客户端请求得到的数据,处理业务的一层,这层实现的方法 UserService接口:每个方法都是一个业务处理的功能,比如登陆功能,注册功能, UserServiceImpl类:通过和UserDaoImpl类组合的方式,调用UserDaoImpl类的对象的方法,具体实现UserService接口的每个方法。

4.web显示层,其实包含两层,一层是前端的代码,另一层当前端显示层用户将数据输入到前端页面,并且点击提交之后,页面会先到servlet请求这一层,将数据进行初步的处理,然后调用service层的功能,进行验证,验证之后,利用请求转发将页面跳转到其他页面。

三,功能分析

用户注册和登陆的实现

  1. 用户注册,需求如下:

    1. 访问注册页面;

    2)填写注册信息,提交给服务器;

    3)服务器应该保存用户;

    4)当用户已经存在--提示用户注册失败,用户名已存在;

    5)当用户不存在,注册成功;

  2. 用户登陆,需求如下:

    1)访问登陆页面;

    2)填写用户名密码后提交;

    3)服务器判断用户是否存在;

    4)如果登陆失败,返回用户名或者密码错误信息;

    5)如果登录成功,返回登陆成功信息;

四,代码实现

1.创建数据库表

数据库为book,建一个用户表为t_user;

drop database if exists book;

create database book;


use book;

create table t_user(
	`id` int primary key auto_increment,
	`username` varchar(20) not null unique,
	`password` varchar(20) not null,
	`email` varchar(100)
);

insert into t_user(`username`,`password`,`email`) values('admin','admin','ethansung@163.com');

select * 
from t_user;

2.pojo类-User类

package com.ethan.pojo;

/**
 * @author ethan
 * @create 2020-08-09 13:30
 */
public class User {
    private int 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 int getId() {
        return id;
    }

    public void setId(int 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 + '\'' +
                '}';
    }
}

3.实现JDBCUtils

该类封装Druid数据库连接池实现数据库数据库连接池以及获取数据库连接,关闭连接的功能,为Dao持久层与数据库交互建立联系;


package com.ethan.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.junit.Test;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author ethan
 * @create 2020-08-09 13:35
 */
public class JDBCUtils {
    @Test
    public void testConnection(){
        for (int i = 0; i < 100; i++) {
            Connection conn = JDBCUtils.getConnection();
            System.out.println(conn);
            JDBCUtils.closeConnection(conn);
        }
    }

    private static DruidDataSource dataSource;
    static {
        try {
            /*
                方法1:
                File f = new File("F:\\FontEndCodeTest\\JavaWebSelf\\Book\\src\\jdbc.properties");
                InputStream is =new FileInputStream(f);
             */
            InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
            Properties pros = new Properties();
            pros.load(is);
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(pros);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    public static Connection getConnection(){
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return conn;
    }

    /**
     * 关闭连接,放回数据库连接池
     * @param conn
     */
    public static void closeConnection(Connection conn){
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}


4.实现Dao持久层

Dao持久层通过java代码实现与数据库的交互,实现CRUD功能; DAO:Data Access Object访问数据库信息的类和接口,包括了对数据(一般是JavaBean对象)的CRUD(Create、Retrival、Update、Delete),而不包含任何业务相关的信息BaseDao抽象类:包括了对数据(一般是JavaBean对象)的CRUD(Create、Retrival、Update、Delete),具有复用性,不对具体业务。一般使用DBUtils工具类库进行封装。

package com.ethan.dao.impl;


import com.ethan.utils.JDBCUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * @author ethan
 * @create 2020-08-09 14:30
 */
public abstract class BaseDao {
    private QueryRunner runner = new QueryRunner();

    /**
     * 用于执行insert、update、delete操作
     * @param sql
     * @param args
     * @return 返回-1说明sql语句执行失败
     */
    public int update(String sql,Object...args){
        Connection conn = JDBCUtils.getConnection();
        try {
            return runner.update(conn,sql,args);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.closeConnection(conn);
        }
        return -1;
    }

    /**
     * 查询返回一个bean对象的sql查询方法
     * @param type javabean类类型
     * @param sql   sql语句
     * @param args  可变参数
     * @param <T>   JavaBean返回值类型
     * @return  返回查询到的javabean对象
     */
    public <T> T queryForOne(Class<T> type,String sql,Object...args){
        Connection conn = JDBCUtils.getConnection();
        try {
            BeanHandler<T> rsh = new BeanHandler<T>(type);
            T query = runner.query(conn, sql, rsh, args);
            return query;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.closeConnection(conn);
        }
        return null;
    }

    /**
     * 查询一组javabean对象
     * @param type  返回对象的类型
     * @param sql   执行的sql语句
     * @param args  sql的参数
     * @param <T>   返回值类型的泛型
     * @return
     */
    public <T> List<T> queryForList(Class<T> type,String sql,Object...args){
        Connection conn = JDBCUtils.getConnection();
        try {
            List<T> queryList = runner.query(conn, sql, new BeanListHandler<T>(type), args);
            return queryList;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeConnection(conn);
        }

        return null;
    }

    public Object queryForSingleValue(String sql,Object...args){
        Connection conn = JDBCUtils.getConnection();
        try {
            Object query = runner.query(conn, sql, new ScalarHandler(), args);
            return query;
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeConnection(conn);
        }
        return null;

    }
}

UserDao接口:具体的某个JavaBean类的接口,接口内定义的抽象方法都是具体的JavaBean对象需要的业务功能,比如xxx。

package com.ethan.dao;

import com.ethan.pojo.User;


/**
 * @author ethan
 * @create 2020-08-09 15:27
 */
public interface UserDao {
    /**
     * 根据用户名查询用户信息
     * @param name 用户名
     * @return  返回null,该用户没有注册
     */
    public User queryUserByUsername(String name);

    /**
     * 根据用户名和密码查询用户信息
     * @param name  用户名
     * @param Password  用户密码
     * @return  返回null,该用户没有注册
     */
    public User queryUserByUsernameandPassword(String name,String Password);

    /**
     * 保存用户信息
     * @param user
     * @return  返回-1表示保存失败
     */
    public int saveUser(User user);
}


UserDaoImpl类:继承BaseDao抽象类,可以调用通用的BaseDao抽象类的方法,实现UserDao接口,实现UserDao接口中业务的方法。

package com.ethan.dao.impl;

import com.ethan.dao.UserDao;
import com.ethan.pojo.User;

/**
 * @author ethan
 * @create 2020-08-09 15:34
 */
public class UserDaoImpl extends BaseDao implements UserDao {
    @Override
    public User queryUserByUsername(String name) {
        String sql = "select id,username,email from t_user where username=?";
        User user = queryForOne(User.class, sql, name);
        return user;
    }

    @Override
    public User queryUserByUsernameandPassword(String name, String password) {
        String sql = "select id,password,username,email from t_user where username=? and password=?";
        User user = queryForOne(User.class, sql, name,password);
        return user;
    }

    @Override
    public int saveUser(User user) {
        String sql = "insert into t_user(username,password,email) values(?,?,?)";
        int updateCount = update(sql, user.getUsername(), user.getPassword(), user.getEmail());
        return updateCount;
    }
}

5.实现Service层

Service业务层,这一层处理从客户端请求得到的数据,处理业务的一层,这层实现的方法 UserService接口:每个方法都是一个业务处理的功能,比如登陆功能,注册功能,

package com.ethan.service;

import com.ethan.pojo.User;

/**
 * 一个业务,一个功能,一个方法
 * @author ethan
 * @create 2020-08-09 16:06
 */
public interface UserService {
    /**
     * 注册用户
     * @param user
     */
    public void registerUser(User user);

    /**
     * 用户登录
     * @param user
     * @return  返回null,登录失败,非空,登录成功
     */
    public User login(User user);

    /**
     * 检查用户名是否可用
     * @param username
     * @return  返回true代表用户名已存在,返回false表示用户名可用
     */
    public boolean existsUsername(String username);
}

UserServiceImpl类:通过和UserDaoImpl类组合的方式,调用UserDaoImpl类的对象的方法,具体实现UserService接口的每个方法。

package com.ethan.service.impl;

import com.ethan.dao.UserDao;
import com.ethan.dao.impl.BaseDao;
import com.ethan.dao.impl.UserDaoImpl;
import com.ethan.pojo.User;
import com.ethan.service.UserService;


/**
 * @author ethan
 * @create 2020-08-09 16:10
 */
public class UserServiceImpl implements UserService {

    /**
     * 多用组合,少用继承。
     */
    private UserDao userDao = new UserDaoImpl();
    @Override
    public void registerUser(User user) {
         userDao.saveUser(user);
    }

    @Override
    public User login(User user) {
        return userDao.queryUserByUsernameandPassword(user.getUsername(),user.getPassword());
    }

    @Override
    public boolean existsUsername(String username) {
        User user = userDao.queryUserByUsername(username);
        if(user == null){
            System.out.println("用户名可用!");
            return false;
        }else{
            System.out.println("用户名已经存在!");
            return true;
        }
    }
}

6.实现Servlet类(Web展示层)

web显示层,其实包含两层,一层是前端的代码,另一层当前端显示层用户将数据输入到前端页面,并且点击提交之后,页面会跳转到servlet请求这一层, 将数据进行初步的处理,然后调用service层的功能,进行验证,验证之后,利用请求转发将页面跳转到其他页面。

注册提交后跳转到RegisterServlet进行注册功能的验证和处理

package com.ethan.web;

import com.ethan.pojo.User;
import com.ethan.service.UserService;
import com.ethan.service.impl.UserServiceImpl;

import javax.servlet.RequestDispatcher;
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.security.PrivateKey;

/**
 * @author ethan
 * @create 2020-08-10 20:50
 */
public class RegisterServlet extends HttpServlet {


    private UserService userService = new UserServiceImpl();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {


         //1.获取到表单请求过来的参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String repwd = req.getParameter("repwd");
        String email = req.getParameter("email");
        String code = req.getParameter("code");

        //2.验证 验证码是否正确 ===要求验证码写死,为abcde
        if("abcde".equalsIgnoreCase(code)){
            //3.若验证码正确,检查用户名是否可用
            if(userService.existsUsername(username)){
                //用户名不可用,返回注册页面
                System.out.println("用户名[ "+username+" ]已存在!");
                RequestDispatcher requestDispatcher = req.getRequestDispatcher("/pages/user/regist.html");
                requestDispatcher.forward(req,resp);
            }else {
                //用户名可用,将注册的用户信息调用service层保存到数据库
                userService.registerUser(new User(username,password,email));
                //将用户注册信息保存到数据库之后,页面跳转到注册成功页面
                req.getRequestDispatcher("/pages/user/regist_success.html").forward(req,resp);

            }
        }else{
            //验证码不正确,返回注册页面
            System.out.println("验证码[ "+code+" ]错误!");
            RequestDispatcher requestDispatcher = req.getRequestDispatcher("/pages/user/regist.html");
            requestDispatcher.forward(req,resp);

        }


    }
}

登录提交后跳转到RegisterServlet进行注册功能的验证和处理

package com.ethan.web;

import com.ethan.pojo.User;
import com.ethan.service.UserService;
import com.ethan.service.impl.UserServiceImpl;

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

/**
 * @author ethan
 * @create 2020-08-10 23:21
 */
public class LoginServlet extends HttpServlet {

    private UserService userService = new UserServiceImpl();


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取参数

        String username = req.getParameter("username");
        String password = req.getParameter("password");

        User login = userService.login(new User(username, password, null));
        if(login == null){
            //登录失败,返回登陆界面
            req.getRequestDispatcher("/pages/user/login.html").forward(req,resp);
        }else {
            //登录成功
            req.getRequestDispatcher("/pages/user/login_success.html").forward(req,resp);
        }
    }
}

7.前端代码

1.登录页面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>尚硅谷会员登录页面</title>
	<!--base标签,用来固定相对路径跳转的结果-->
	<base href="http://localhost:8080/book/">
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
</head>
<body>
		<div id="login_header">
			<img class="logo_img" alt="" src="static/img/logo.gif" >
		</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>
								<a href="pages/user/regist.html">立即注册</a>
							</div>
							<div class="msg_cont">
								<b></b>
								<span class="errorMsg">请输入用户名和密码</span>
							</div>
							<div class="form">
								<form action="loginServlet" method="post">
									<label>用户名称:</label>
									<input class="itxt" type="text" placeholder="请输入用户名"
										   autocomplete="off" tabindex="1" name="username" />
									<br />
									<br />
									<label>用户密码:</label>
									<input cla	ss="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;2015
			</span>
		</div>
</body>
</html>

2.登录成功页面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>尚硅谷会员注册页面</title>
	<!--base标签,用来固定相对路径跳转的结果-->
	<base href="http://localhost:8080/book/">
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<style type="text/css">
	h1 {
		text-align: center;
		margin-top: 200px;
	}
	
	h1 a {
		color:red;
	}
</style>
</head>
<body>
		<div id="header">
				<img class="logo_img" alt="" src="static/img/logo.gif" >
				<div>
					<span>欢迎<span class="um_span">韩总</span>光临尚硅谷书城</span>
					<a href="pages/order/order.html">我的订单</a>
					<a href="index.html">注销</a>&nbsp;&nbsp;
					<a href="index.html">返回</a>
				</div>
		</div>
		
		<div id="main">
		
			<h1>欢迎回来 <a href="index.html">转到主页</a></h1>
	
		</div>
		
		<div id="bottom">
			<span>
				尚硅谷书城.Copyright &copy;2015
			</span>
		</div>
</body>
</html>

3.注册页面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>尚硅谷会员注册页面</title>
	<!--base标签,用来固定相对路径跳转的结果-->
	<base href="http://localhost:8080/book/">
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
	<script type="text/javascript" src="static/script/jquery-1.7.2.js"></script>
	<script type="text/javascript">
		//页面加载完成之后
		$(function () {
			//1.给最后的注册按钮绑上监听事件
			$("#sub_btn").click(function () {
			/*
			 	1. 验证用户名,要求:必须是字母,数字下划线组成,长度为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;
				}


			/*
			 	2. 验证密码,要求:必须是字母,数字下划线组成,长度为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;
                }


			/*
			 	3. 验证确认密码,要求:和密码填写一致;
			  */
				// 1.获取确认密码的内容
				var repwdText = $("#repwd").val();
				// 2.和密码进行比较
                if (repwdText != passwordText){
                    $("span.errorMsg").text("确认密码和密码不一致!");
                    return false;
				}
				// 3.提示用户
			/*
			 	4. 验证邮箱,要求:符合邮箱的正确格式;
			  */
				// 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;
				}
			/*
			 	5. 验证码,只验证用户输入了验证码
			  */
				var codeText = $("#code").val();
				//去掉内容的前后空格
				alert("去空格之前:["+codeText+"]");
                codeText = $.trim(codeText);
                alert("去空格之后:["+codeText+"]");
                if( codeText == null || codeText == ""){
                    $("span.errorMsg").text("验证码不能为空!");
                    return false;
				}
				//当验证用户名合法之后,去掉不合法字样
                $("span.errorMsg").text("");
            })

        })
	</script>
<style type="text/css">
	.login_form{
		height:420px;
		margin-top: 25px;
	}
	
</style>
</head>
<body>
		<div id="login_header">
			<img class="logo_img" alt="" src="static/img/logo.gif" >
		</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="registerServlet" 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>
									<img alt="" src="static/img/code.bmp" style="float: right; margin-right: 40px">
									<input class="itxt" type="text" name="code" style="width: 150px;" id="code"/>
									<br />
									<br />
									<input type="submit" value="注册" id="sub_btn" />
									
								</form>
							</div>
							
						</div>
					</div>
				</div>
			</div>
		<div id="bottom">
			<span>
				尚硅谷书城.Copyright &copy;2015
			</span>
		</div>
</body>
</html>

4.注册成功页面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>尚硅谷会员注册页面</title>
	<!--base标签,用来固定相对路径跳转的结果-->
	<base href="http://localhost:8080/book/">
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<style type="text/css">
	h1 {
		text-align: center;
		margin-top: 200px;
	}
	
	h1 a {
		color:red;
	}
</style>
</head>
<body>
		<div id="header">
				<img class="logo_img" alt="" src="static/img/logo.gif" >
				<span class="wel_word"></span>
				<div>
					<span>欢迎<span class="um_span">韩总</span>光临尚硅谷书城</span>
					<a href="order/order.html">我的订单</a>
					<a href="index.html">注销</a>&nbsp;&nbsp;
					<a href="index.html">返回</a>
				</div>
		</div>
		
		<div id="main">
		
			<h1>注册成功! <a href="index.html">转到主页</a></h1>
	
		</div>
		
		<div id="bottom">
			<span>
				尚硅谷书城.Copyright &copy;2015
			</span>
		</div>
</body>
</html>

总结

1.新的知识点

  1. 表单传递数据特别是密码之类的,用dopost请求。 原因:get方式会把请求参数拼接到请求路径上(URL上面会把你的输入信息显示出来),并且有长度限制。post方式把请求参数显示到请求体中(提交的数据封装到请求体中,不会显示出现在URL中),没有长度限制。

2.运用到了请求转发,注意base标签的作用,和相对路径和绝对路径。

  1. 学习到IDEA的debug调试