修改web目录下所有HTML页面为jsp页面

1,在HTML页面顶行添加page指令

2,修改文件名后缀为.jsp

14-书城项目(第三阶段)_java

注意有的页面中引用了其他页面,这些引用页面的后缀也要改。选择pages目录,Ctrl+shift+r

14-书城项目(第三阶段)_表单_02

抽取所有jsp页面中公共内容

公共内容的jsp页面在pages下新建目录common中

14-书城项目(第三阶段)_验证码_03

将其他jsp页面中用到这个div的地方改为静态包含

14-书城项目(第三阶段)_用户名_04

这三行是每个页面都有的,将它放在common目录下

14-书城项目(第三阶段)_java_05

替换掉所有页面中的base、link、script标签

14-书城项目(第三阶段)_jsp页面_06

页脚的内容也是所有页面都有的,将它放在common目录下

14-书城项目(第三阶段)_用户名_07

替换掉所有页面中的页脚

14-书城项目(第三阶段)_jsp页面_08

在后台的目录manager中,这些是公共的

14-书城项目(第三阶段)_验证码_09

替换到该目录中的jsp页面中

14-书城项目(第三阶段)_java_10

动态的base标签值

在本地访问本机ip时,以style.css这个文件为例,客户端请求的地址还是localhost,这是因为base标签固定写的是localhost。而如果是其他主机访问,就变为其他主机请求本地的style.css文件,结果就会出错

14-书城项目(第三阶段)_表单_11

修改head.jsp中的base标签

14-书城项目(第三阶段)_验证码_12

变为请求服务器的资源

14-书城项目(第三阶段)_表单_13

表单提交失败的错误回显

当用户登录或注册失败,返回登录或注册页面时,应该给用户一些提示和保留个别表单项

LoginServlet.java

14-书城项目(第三阶段)_java_14

login.jsp

14-书城项目(第三阶段)_java_15

RegistServlet.java,用户名错误或验证码错误的情况下都需要回显

14-书城项目(第三阶段)_验证码_16

regist.jsp

14-书城项目(第三阶段)_用户名_17

当登录时密码错误

14-书城项目(第三阶段)_jsp页面_18

当注册时用户名已存在或验证码错误

14-书城项目(第三阶段)_验证码_19

14-书城项目(第三阶段)_用户名_20

代码优化一:合并LoginServlet和RegistServlet程序为UserServlet程序

在实际项目开发中,一个模块一般只使用一个Servlet程序。以这个项目为例,UserServlet既实现登录功能,也实现了注册功能

14-书城项目(第三阶段)_表单_21

package com.atguigu.web;

import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
import com.atguigu.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;

public class UserServlet extends HttpServlet {

private UserService userService = new UserServiceImpl();

protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");

User loginUser = userService.login(new User(null, username, password, null));
if (loginUser == null) {
// 把错误信息和要回显的表单项信息保存到Request域中
// 只要是要回显的信息,就将其放在Request域中
req.setAttribute("msg", "用户名或密码错误");
req.setAttribute("username", username);
req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp);
} else {
req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);
}
}

protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1,获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
// 2,校验验证码是否正确,这里先使用固定验证码
if ("abcde".equalsIgnoreCase(code)) {
// web层不能直接调用Dao层,要通过Service层
if (userService.existUsername(username)) {
System.out.println("用户名[" + username + "]已存在");
// 把错误信息和要回显的表单项信息保存到Request域中
req.setAttribute("msg", "用户名已存在");
req.setAttribute("username", username);
req.setAttribute("email", email);
// 请求转发,用户名已存在,跳转到注册页面
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
} else {
// 将注册的用户信息保存到数据库
userService.registUser(new User(null, username, password, email));
// 用户名可使用,跳转至注册成功页面
req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req, resp);
}
} else {
// 把错误信息和要回显的表单项信息保存到Request域中
req.setAttribute("msg", "验证码错误");
req.setAttribute("username", username);
req.setAttribute("email", email);
System.out.println("验证码[" + code + "]错误");
// 请求转发,跳回注册页面
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 是登录时返回login,是注册时返回regist
String action = req.getParameter("action");
if ("login".equals(action)) {
login(req, resp);
} else if ("regist".equals(action)) {
regist(req, resp);
}
}
}

web.xml

14-书城项目(第三阶段)_表单_22

login.jsp

14-书城项目(第三阶段)_表单_23

regist.jsp

14-书城项目(第三阶段)_表单_24

代码优化二:使用反射优化大量else if代码

用户模块的功能除了登录和注册,还有修改用户信息、修改密码、绑定手机号、绑定邮箱、注销用户等,每个功能都有一个隐藏域对应到doPost()中都是一个else if语句,这样一来代码就显得臃肿

使用反射的例子

package com.atguigu.test;

import java.lang.reflect.Method;

public class UserServletTest {

public void login() {
System.out.println("这是login()被调用了");
}

public void regist() {
System.out.println("这是regist()被调用了");
}

public void updateUser() {
System.out.println("这是updateUser()被调用了");
}

public void updateUserPassword() {
System.out.println("这是updateUserPassword()被调用了");
}

public static void main(String[] args) {
String action = "updateUser";

try {
// 返回类的“action”方法
Method method = UserServletTest.class.getDeclaredMethod(action);
// 调用该对象的“action”方法
method.invoke(new UserServletTest());
} catch (Exception e) {
e.printStackTrace();
}
}
}

使用反射后的doPost()

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 是登录时返回login,是注册时返回regist
String action = req.getParameter("action");
try {
// 通过当前对象获取类,返回类的“action”方法,该方法需要两个参数
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
// 调用当前对象的“action”方法
method.invoke(this, req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}

代码优化三:抽取BaseServlet程序

在图书管理模块中,BookServlet程序做的事情和UserServlet一致,都是先获取action参数值,再通过反射获取action对应的业务方法,然后通过反射调用业务方法,所以可以将二者的相同部分抽取出来

新建BaseServlet.java,继承HttpServlet,将UserServlet的doPost()剪切过来

14-书城项目(第三阶段)_java_25

UserServlet改为继承BaseServlet,以后的Servlet都继承BaseServlet

14-书城项目(第三阶段)_java_26

BeanUtils工具类的使用

BeanUtils工具类的功能之一是可以一次性的把请求的所有参数注入到JavaBean中,BeanUtils是第三方工具类,需要导包

将两个jar包复制到lib下并添加到类库中

14-书城项目(第三阶段)_jsp页面_27

简单测试,在UserServlet的regist()中加入代码

14-书城项目(第三阶段)_jsp页面_28

14-书城项目(第三阶段)_表单_29

14-书城项目(第三阶段)_验证码_30

将注入的功能写成方法

package com.atguigu.utils;

import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.http.HttpServletRequest;

public class WebUtils {

public static void copyParamToBean(HttpServletRequest req, Object bean) {
try {
System.out.println("注入之前:" + bean);
// 将请求的所有参数都注入到user对象中
BeanUtils.populate(bean, req.getParameterMap());
System.out.println("注入之后:" + bean);
} catch (Exception e) {
e.printStackTrace();
}
}
}

UserServlet.java

14-书城项目(第三阶段)_java_31

细节说明,打印map中的键值对内容

14-书城项目(第三阶段)_表单_32

点击注册时所有提交过来的内容,这些信息对应到User类的各个属性,然后通过属性对应的set()设置User对象的属性值

14-书城项目(第三阶段)_java_33

小的优化,WebUtils.java。将方法声明为泛型,在用方法的返回值赋值时就不用再做强转;参数HttpServletRequest改为Map,是因为HttpServletRequest是web层的,最好不要出现在utils包下,避免如果在其他层被调用时出现web层的内容

14-书城项目(第三阶段)_用户名_34

UserServlet.java

14-书城项目(第三阶段)_java_35