本项目根据JavaWeb的学习过程分为几个部分,分别是表单验证、用户注册与登录、修改所有HTML页面为JSP页面……其中每一部分都对应JavaWeb的一些技术栈,由浅入深,从而对JavaWeb有一个整体的把握。
温馨提醒:
1)本文干货较多,如果只想了解其中的某一部分,可以利用左边目录进行索引。
2)该项目所需要用到的技术有Java、MySQL、HTML、CSS、JavaScript、JQuery、XML、Tomcat、Servlet等,需要有相应基础的同学才能更好的学习该部分内容。想了解这些技术,可查看我的其它文章,下面为链接:
Servlet:Servlet必知必会
3)代码的具体实现可以参考代码中的注释,如果由于注释不清楚而不明白相应原理,可以与作者私聊,欢迎互相交流、进步。
运用JQuery技术来实现动态注册 ,同时实现表单的验证以及上传,即验证注册信息是否满足要求。
我们需要利用JQuery技术来实现表单的验证,那么该HTML文件中会有一些链接,这里先做一个约定:即在没有使用框架之前,我们使用base+相对路径,在使用框架后,使用的是绝对路径。其中,运用Jquery技术来实现动态注册,其中#username的目的就是#id选择器;利用正则表达式来实现表单数据的验证(验证其是否满足格式);
<html>
<head>
<meta charset="UTF-8">
<title>尚硅谷会员注册页面title>
<base href="http://localhost:8080/book_market/">
<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">
// 页面加载完成之后
//运用Jquery技术来实现动态注册,其中#username的目的就是#id选择器 KO by sharm. 2020.11.6
$(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;
}
// 邮箱验证:[email protected]
//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>
<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="registServlet" 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;" name="code" 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 ©2015
span>
div>
body>
html>
第一阶段中,我们只接触到了前端网页,并没有接触到前端和后端之间是如何交互的,接下来,我将利用一些技术来使得前端和后端的内容相融合。
上图中,蓝色代表数据处理步骤,红色代码不同的技术。通过对项目进行分层,完成对项目的解耦,解耦就是为了降低代码的耦合度,这样就不会使得代码牵一发而动全身。相应地,得到了如下不同的包。
架构 | 包名 |
---|---|
web层 | sharm.web |
service层 | sharm.service/sharm.service.imp |
dao持久层 | sharm.dao/sharm.dao.imp |
测试包 | sharm.test |
工具类 | sharm.utils |
实体Bean对象 | sharm.pojo |
在IDEA中搭建开发环境,建立相应的包,目录结构如图2.1所示,其中pages、static文件夹是给定的,可以通过这个地址【GitHub链接】下载我的整个工程文件。
首先,按照下图所示,在IDEA中建立一个连接MySQL服务器的控制台。如果有不清楚MySQL服务器不知道怎么下载与安装的,可以参考参考资料【点击】。
打开MySQL命令行窗口。输入如下所示的MySQL命令,生成我们的数据库和表,其中“sharm”为项目管理员。
#我的目的是创建一个包含ID号(自增)、用户名、密码、邮箱的表
#1 创建一个名为sharm_schema数据库
drop database if exists sharm_schema;
create database sharm_schema;
#1 创建一个名为book的表
use sharm_schema;
create table book(
#2 初始话定义不同变量
#其中ID为自增;用户名唯一且非空;密码非空;邮箱没有要求
`id` int primary key auto_increment,
`username` varchar(20) not null unique,
`password` varchar(32) not null ,
`email` varchar(100)
);
insert into book(`username`,`password`,`email`) values('sharm','123456','[email protected]');
select * from book;
在sharm.pojo中创建User类,输入如下代码,从而创建JavaBean对象。
package sharm.pojo;
/**
* 数据库表对应的JavaBean类
*/
public class User {
/**因为Int类的默认值为0,而Integer的默认值为null*/
private Integer id;
private String username;
private String password;
private String email;
//无参构造器
public User() {
}
//有参构造器
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 + '\'' +
'}';
}
}
由于项目需要,所以需要导入如下图所示的五个jar包,jar包的下载地址见第二章末尾【链接】。
在src源码目录下新建名为jdbc.properties的文件,然后在其中书写如下所示代码。该属性配置文件是为了连接数据库,所以其中的参数需要与自身的数据库的参数相对应。
//为了防止程序出现错误,在书写该配置文件时请删掉注释
username=root //MySQL数据库用户名
password=123456 //MySQL数据库密码
url=jdbc:mysql://localhost:3306/sharm_schema?useUnicode=true&characterEncoding=utf8
//上面这句如果不在url后加入?useUnicode=true&characterEncoding=utf8这句,则会出现编码错误
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
在sharm.utils工具包中新建一个JdbcUtils工具类。该工具类的目的是为了创建数据库连接池,同时获取数据库连接池中的连接与关闭。代码如下所示:
package sharm.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtils {
private static DruidDataSource dataSource;
//初始化块会在“创建类的实例时”执行,而静态初始化块值会优先普通初始化块执行,且执行一次
//还有一种方法,在类中加入一个main方法,main方法一执行,类就会执行,那么代码块就会执行
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,说明获取连接失败
有值就是获取连接成功
*/
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();
}
}
}
}
在实际开发环境中,我们需要对类的功能进行测试。这里,我们在sharm.text目录下新建JdbcUtilsTest测试类,代码如下所示,从而完成测试。
package sharm.test;
import sharm.utils.JdbcUtils;
import org.junit.Test;
import java.sql.Connection;
/**
* 测试数据库连接池的连接与关闭
*/
public class JdbcUtilsTest {
@Test
public void testJdbcUtils(){
//for循环的方法就是获取100次连接池的连接
for (int i = 0; i < 100; i++){
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
//数据库的连接池每次用完一定要释放
JdbcUtils.close(connection);
}
}
}
该类为Dao持久层的超类,其定义了与数据库交互的具体行为,但其本生不需要对象实例,所以设置其为抽象类。在sharm.dao.imp包下新建BaseDao抽象类,代码如下所示:
package sharm.dao.impl;
import sharm.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;
/**
* 只负责和数据库交互,如增删改查
* BaseDao类是给别人复制代码的,所以不需要对象实例,所以设置其为抽象类
* @author Sharm
*/
public abstract class BaseDao {
//DbUtils操作数据库
private QueryRunner queryRunner=new QueryRunner();
/**
* update() 方法用来执行:Insert\Update\Delete语句
* @return 如果返回-1,说明执行失败
返回其他则表示增加的行数(这一部分是源码)
*/
public int updata(String sql,Object... args){
Connection connection = JdbcUtils.getConnection();
//sql语句;sql语句中的值,可变长参数
try {
return queryRunner.update(connection,sql,args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(connection);
}
return -1;
}
/**
* 先验知识:1)泛型:J2SE 1.5中新增了"泛型"的机制,可以在一定条件下把一个类型参数化。
* 例如,可以在编写一个类的时候,把一个方法的形参的类型用一个标识符(如T)来代表,
* 至于这个标识符到底表示什么类型,则在生成这个类的实例的时候再行指定。这一机制可以
* 用来提供更充分的代码重用和更严格的编译时类型检查。不过泛型机制却不能和个数可变的形参配合使用。
* 2)可变参数:本质上还是数组
* @param type 返回的对象类型
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @param 返回的类型的泛型。第一个表示是泛型;第二个表示返回的是T类型的数据;第三个限制参数类型为T
* @return
*/
public <T>T queryForOne(Class<T> type,String sql,Object... args){
Connection con = JdbcUtils.getConnection();
try {
//查询时,query中BeanHandler中的type类型就是执行后返回参数的类型
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 返回的类型的泛型
* @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;
}
}
在sharm.dao目录下新建一个UserDao接口,用于约束类必须实现的方法。代码如下所示:
//通过修改包名来移动接口的存放位置
package sharm.dao;
import sharm.pojo.User;
/**
* 约束类必须实现的方法。注意:接口存放的位置
*/
public interface UserDao {
/**
* 1. 验证用户名是否有效:即该用户名是否可以注册——根据用户名查询用户的信息
* @param username 待查的用户名
* @return 如果返回null,则该用户不存在;否则则返回用户信息
*/
public User queryUserByUsername(String username);
/**
* 2. 将注册信息保存到数据库
* @param user 待保存的用户信息
* @return 返回-1表示操作失败,其他是sql语句影响的行数
*/
public int saveUser(User user);
/**
* 3. 登录操作:根据用户名和密码查询用户信息(1和2是注册操作,3是登录操作)
* @param username 待输入的用户信息
* @param password 待输入的密码
* @return 如果返回null,说明用户名或密码错误,反之亦然
*/
public User queryUserByUsernameAndPassword(String username, String password);
}
在sharm.dao.impl包下新建UserDaoImp实现类,用于Dao持久层具体功能的实现,代码如下所示:
package sharm.dao.impl;
import sharm.dao.UserDao;
import sharm.pojo.User;
public class UserDaoImp extends BaseDao implements UserDao {
@Override
public User queryUserByUsername(String username) {
String sql="select `id`,`username`,`password`,`email` from book where username=?";
//继承的抽象超类的方法,直接使用
return queryForOne(User.class,sql,username);
}
@Override
public int saveUser(User user) {
String sql="insert into book(`username`,`password`,`email`) values(?,?,?)";
return updata(sql,user.getUsername(),user.getPassword(),user.getEmail());
}
@Override
public User queryUserByUsernameAndPassword(String username, String password) {
String sql="select `id`,`username`,`password`,`email` from book where username = ? and password = ?";
return queryForOne(User.class,sql,username,password);
}
}
在sharm.test新建UserDaoImpTest测试类,用于测试UserDaoImp实现类的功能。代码如下所示:
package sharm.test;
import org.junit.Test;
import sharm.dao.impl.UserDaoImp;
import sharm.pojo.User;
import static org.junit.Assert.*;
public class UserDaoImpTest {
@Test
/**
* 我的目的是为了测试这个方法是否可用,所以,我先实例化后这个方法,
* 然后,在该对象上使用该方法来进行测试。
* 原文是测试接口类,我是为了测试UserDaoImp类
*/
public void queryUserByUsername() {
UserDaoImp userDaoImp = new UserDaoImp();
if (userDaoImp.queryUserByUsername("sharm")==null) {
System.out.println("该用户名可用");
} else {
System.out.println("该用户名已经存在");
}
}
@Test
public void saveUser() {
UserDaoImp userDaoImp = new UserDaoImp();
//原来导入对象是用这个方法
System.out.println(userDaoImp.saveUser(new User(null,"haha","123456","[email protected]")));
}
@Test
public void queryUserByUsernameAndPassword() {
UserDaoImp userDaoImp = new UserDaoImp();
if ( userDaoImp.queryUserByUsernameAndPassword("admin","admin1234") == null) {
System.out.println("用户名或密码错误,登录失败");
} else {
System.out.println("查询成功");
}
}
}
编写测试类除了自己写一个测试文件的方法,还有一种IDEA的快捷键,即在实现类里,Ctrl+shift+T生成测试,具体选项如下图2.4所示:
在sharm.service包下新建UserService接口,该接口用于约束UserService实现类的具体功能,代码如下所示:
package sharm.service;
import sharm.pojo.User;
/**
* 在业务层,我们有哪些业务呢?比如:登录是一个业务,注册是一个业务,检查是一个业务。那么接口就是规范好业务层需要进行的业务。
* Service层的功能要与Dao层相对应
* Dao层:queryUserByUsername → Service层:existsUsername
* Dao层:saveUser → Service层:registUser
* Dao层:queryUserByUsernameAndPassword → Service层:login
*/
public interface UserService {
/**
* 检查用户名是否可用
* @param username 待注册的用户名
* @return 返回true表示用户名已存在,返回false表示用户名可用
*/
public boolean existsUsername(String username);
/**
*
* @param user 待注册的用户
* @return 若返回-1,则注册失败;返回其他则表示增加的行数
*/
public int registUser(User user);
/**
*
* @param user 待登录的用户
* @return 如果返回null,说明登录失败,返回有值,是登录成功
*/
public User login(User user);
}
在sharm.service.impl包下新建UserServiceImp实现类,用于Service服务层具体功能的实现,代码如下所示:
package sharm.service.impl;
import sharm.dao.UserDao;
import sharm.dao.impl.UserDaoImp;
import sharm.pojo.User;
import sharm.service.UserService;
/**
* Service业务层有两个功能:1)处理业务逻辑;2)调用dao持久层将信息保存到数据库
* 1)功能在方法中体现出来了;那么现在要做的就是功能2)
*/
public class UserServiceImp implements UserService {
// private UserDao userDao=new UserDaoImp(); 原代码中运用了多态,但userDao会丢失子类的方法,不过由于子类没有增加方法,所以不影响
private UserDaoImp userDaoImp=new UserDaoImp();
@Override
public boolean existsUsername(String username) {
//强的,sharm,这都被你想出来了
return (userDaoImp.queryUserByUsername(username)!=null);
}
@Override
public int registUser(User user) {
return userDaoImp.saveUser(user);
}
@Override
public User login(User user) {
return userDaoImp.queryUserByUsernameAndPassword(user.getUsername(),user.getPassword());
}
}
由于前面有介绍,当不是用SSM框架时,我们的目录结构采用base+相对路径的方法,所以,我们需要修改HTML文件中的路径。同时,由于表单中存在密码,所以表单的上传方法需要修改doPost请求。修改形式如下代码所示,按照这种方式修改HTML页面中的所有路径。
"UTF-8">
尚硅谷会员登录页面</title>
<!--在文件开头加上base标签-->
"http://localhost:8080/book_market/">
<!--修改页面中与base标签相关联的路径-->
type="text/css" rel="stylesheet" href="static/css/style.css" >
</head>
注意:如果由于HTML文本页面过长而导致无法找到所有待修改的路径时,可以先将工程部署到Tomcat服务器上,在浏览器中输入F12,在Network-Name下,标红的路径就是待修改的路径,如过未刷新,就在浏览器上刷新一下。
①:在sharm.web包下新建名为RegistServlet的Servlet的小程序,Java部分代码如下:
package sharm.web;
import sharm.pojo.User;
import sharm.service.impl.UserServiceImp;
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;
public class RegistServlet extends HttpServlet {
//哈哈哈,同dao层之于service层一样,service层之于web层也是这样操作
private UserServiceImp userServiceImp=new UserServiceImp();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1 获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");
//System.out.println(username); 验证表单成功上传到Servlet服务器
//2 优先级最高的是验证码,首先判断验证码是否正确(这里我把验证码规定死为1234)
if("1234".equalsIgnoreCase(code)){
//3 判断用户名是否存在(由于用户名、密码、邮箱的格式我在Jquery中有判断,所以不需要在servlet服务器中再判断)
if (userServiceImp.existsUsername(username)) {
System.out.println("该用户名["+username+"]已经存在,请重新注册");
//跳回注册页面 其中的“/”表示的是web这个目录
RequestDispatcher requestDispatcher=request.getRequestDispatcher("/pages/user/regist.html");
requestDispatcher.forward(request,response);
} else {
//则将注册信息保存到数据库
//从属性到对象,用的是new User(属性1,属性2)
//从对象到属性,用的是User.get的方法
userServiceImp.registUser(new User(null,username,password,email));
request.getRequestDispatcher("/pages/user/regist_success.html").forward(request, response);
}
}else{
System.out.println("验证码[" + code + "]错误");
request.getRequestDispatcher("/pages/user/regist.html").forward(request, response);
}
}
}
②:在web/WEB-INF/web.xml配置文件中配置前端到后端的映像,代码如下所示:
<servlet>
<servlet-name>RegistServletservlet-name>
<servlet-class>sharm.web.RegistServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>RegistServletservlet-name>
<url-pattern>/registServleturl-pattern>
servlet-mapping>
③:HTML页面中注册表单的提交地址和请求方式的修改
<form action="registServlet" method="post">
修改方式与注册部分相同,这里不再做介绍。
①:在sharm.web包下新建名为LoginServlet的Servlet的小程序,Java部分代码如下:
package sharm.web;
import sharm.pojo.User;
import sharm.service.impl.UserServiceImp;
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 {
UserServiceImp userServiceImp=new UserServiceImp();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1 获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2 调用userService.login()登录处理业务
User loginUser = userServiceImp.login(new User(null, username, password, null));
// 如果等于null,说明登录失败!
if (loginUser == null) {
// 跳回登录页面
request.getRequestDispatcher("/pages/user/login.html").forward(request, response);
} else {
//登录成功
//跳到成功页面login_success.html
request.getRequestDispatcher("/pages/user/login_success.html").forward(request, response);
}
}
}
②:在web/WEB-INF/web.xml配置文件中配置前端到后端的映像,代码如下所示:
<servlet>
<servlet-name>LoginServletservlet-name>
<servlet-class>sharm.web.LoginServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>LoginServletservlet-name>
<url-pattern>/loginServleturl-pattern>
servlet-mapping>
③:HTML页面中注册表单的提交地址和请求方式的修改
<form action="loginServlet" method="post">
经过了上述这些步骤之后,一个最基础的JavaEE设计思路就完成了,但最后结果还需要进行检验与调试,因为,一般来讲,是不可能这么顺利的完成一个工程,其还需要经过我们头秃的调试环节。我把自己的整个工程上传到GitHub上,有需要的小伙伴可以参考参考,同时可以指出我的错误,大家一起学习。接下来将进行第三阶段的学习。
今天先休息一下,迟点再码字……码字不易,干货连连,有兴趣的小伙伴点个赞呗,大家相互学习。