第一阶段:主要是通过jQuery对注册页面的用户名+密码+邮箱等作出的一些限制
第二阶段: 实现用户注册和登录
第三阶段:主要是优化注册和登录,给用户一些友好的信息提示
步骤:
1、页面jsp动态化
- 在html页面顶行添加page指令
- 修改文件后缀名为:.jsp
- 使用IDEA搜索替换.html为.jsp
2、抽取页面中相同的内容
1)登录成功后的菜单
<div> <span>欢迎<span class="um_span">您</span>光临尘封网书城</span> <a href="order/order.jsp">我的订单</a> <a href="index.jsp">注销</a> <a href="index.jsp">返回</a> </div>
2)head中的css、jquery、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>
发现上面的ip地址是写死了,这样代码由本地部署到服务器上就很容易报错,所以我们需要动态获取base的地址
<%-- Created by IntelliJ IDEA. User: wufq Date: 2021/7/1 Time: 15:16 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <% //EL表达式pageContext对象的使用。 //动态获取地址 String basepATH = request.getScheme() //获取服务器请求的协议 +"://" +request.getServerName() +":" +request.getServerPort() +request.getContextPath() //获取当前工程路径 +"/"; %> <%--<%=basepATH%>--%> <base href="<%=basepATH%>"> <link type="text/css" rel="stylesheet" href="static/css/style.css" > <script type="text/javascript" src="static/script/jquery-1.7.2.js"></script>
3)每个页面的页脚
<div id="bottom"> <span> 尘封网.Copyright ©2013 </span> </div>
4)manager模块的菜单
<div> <a href="book_manager.jsp">图书管理</a> <a href="order_manager.jsp">订单管理</a> <a href="index.jsp">返回商城</a> </div>
以上内容都抽取以后,在对应的文件内引入jsp的静态包含
如: <%--静态包含登录成功后的菜单--%> <%@include file="/pages/common/login_seccess.jsp"%>
3、登录、注册错误提示以及表单里面的内容回显
当我们账号或者密码输入错误以后,希望界面弹出提示信息并且用户名的文本框显示之前输入的用户名
===登录错误提示和回显信息===
1)首先在LoginServlet类内把错误信息和用户名保存到域中
if(loginUser ==null){ // System.out.println("登录失败!"); //把错误信息和回显的用户名保存到request域中 req.setAttribute("msg","用户名或密码错误!"); req.setAttribute("username",username); req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp); }else { System.out.println("欢迎["+username+"]登录尘封网"); req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp); }
2)修改login.jsp页面,显示回显信息
<div class="msg_cont"> <b></b> <span class="errorMsg"> <% String msg =(String)request.getAttribute("msg"); %> <%=msg==null?"请输入用户名和密码":msg%> </span> </div> <form action="loginServlet" method="post"> <label>用户名称:</label> <% String user =(String)request.getAttribute("username"); %> <input class="itxt" type="text" placeholder="请输入用户名" autocomplete="off" tabindex="1" name="username" value="<%=user==null?"":user%>" />
===注册错误提示和回显信息和登录一样===
4、BaseServlet的抽取
在实际项目开发中,一个模块,一般只使用一个Servlet程序
代码优化一:代码优化:合并LoginServlet和RegistServlet程序为UserServlet
为什么合并?
查看login.jsp和regist.jsp文件发现?两种发送给服务端的方式都是一样的
<form action="LoginServlet" method="post"> <input type="hidden" name="action" value="login"> <form action="RegistServlet" method="post"> <input type="hidden" name="action" value="regist">
服务端的LoginServlet和RegistServlet里面的方法是doPost方法,主要也是通过获取name=action然后分别判断到底是login还是regist
String action = req.getParameter("action"); if("login".equals(action)){ login(req, resp);//处理登录业务 }else if("regist".equals(action)){ regist(req, resp); //处理注册业务 }
----> UserServlet代码
package com.wufq.web; import com.wufq.pojo.User; import com.wufq.service.UserService; import com.wufq.service.impl.UserServiceImpl; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @Description * @Author wufq * @Version * @Date 2021/7/1 19:52 */ public class UserServlet extends BaseServlet{ private UserService userService = new UserServiceImpl(); private 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、检查验证码是否正确 === 写死,要求验证码为:abcde (一般验证码由服务器生成,这个先写死) if("abcde".equalsIgnoreCase(code)){ // 3、验证码正确,在继续检查用户名是否可用 if(userService.existesUserName(username)){ //用户名存在,跳回注册页面 // System.out.println("用户名["+username+"]已存在"); req.setAttribute("msg","用户名已存在"); req.setAttribute("username",username); req.setAttribute("email",email); req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp); }else { //用户名不存在,调用UserService保存在数据库,并且页面跳转到注册成功页面 userService.registUser(new User(null,username,password,email)); req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp); } }else{ // 4、不正确,页面跳转仍然跳转到注册页面 System.out.println("验证码["+code+"]错误"); req.getRequestDispatcher("pages/user/regist.jsp").forward(req,resp); } } private void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ // 1、获取请求的参数 String username = req.getParameter("username"); String password = req.getParameter("password"); // 2、调用userService.login()登录处理业务 User loginUser = userService.login(new User(null, username, password, null)); if(loginUser ==null){ // System.out.println("登录失败!"); //把错误信息和回显的用户名保存到request域中 req.setAttribute("msg","用户名或密码错误!"); req.setAttribute("username",username); req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp); }else { System.out.println("欢迎["+username+"]登录尘封网"); req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action = req.getParameter("action"); if("login".equals(action)){ login(req, resp); }else if("regist".equals(action)){ regist(req, resp); } } } }
---->修改Login.jsp、regist.jsp内请求方式
代码优化二:优化UserServlet中doPost方法
String action = req.getParameter("action"); if("login".equals(action)){ login(req, resp); }else if("regist".equals(action)){ regist(req, resp); }
当前来讲只有登录和注册,如果后面还有其他的业务,比如:添加用户,修改用户信息,修改密码等,那么每次都增加一个else if,代码会很繁琐,所以需要优化
---观察发现,不管是login还是regist判断都是根据前端的action来判断并执行对应的方法(login),所以可以用反射来替代if这种判断来获取起方法名以及执行
public abstract class BaseServlet extends HttpServlet{ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action = req.getParameter("action"); try { // //通过反射获取login,regist方法 Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class); //调用方法 method.invoke(this,req, resp); } catch (Exception e) { e.printStackTrace(); } } }
解释:
this.getClass() 是获取类对象,this指的是当前对象,这里特殊,一般用的是BaseServlet.getClass()来获取
.getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class); 获取方法名对象,action是方法名,后面两个是参数
method.invoke(this,req, resp); 这是执行方法,this是对象,后面两个是方法的参数
这里面还缺少一个对象的声明:this.getClass().newInstance();
----上面那部分代码也是公共的,所以封装成一个公用的类,设置成abstract,后面的UserServlet继承即可
5、数据的封装和抽取BeanUtils的使用
为什么要封装BeanUtils工具类?-->不管是登录还是注册,都需要获取请求参数,然后封装成User对象,这两个功能参数还少,如果是一个参数与特别多的功能,那这部分的工作就很繁琐并且代码也臃肿,所以就用到了BeanUtils工具类封装
String username = req.getParameter("username"); String password = req.getParameter("password"); User loginUser = userService.login(new User(null, username, password, null));
BeanUtils工具类的其中一个作用:它可以一次性的把所有的请求参数注入到javaBean中
BeanUtils他不是jdk的类,而是第三方的工具类,所以需要需要导包
1)需要导入的jar包 (必须导两个,少导一个的话会报错)
commons-beanutils-1.8.0.jar
commons-logging-1.1.1.jar
2)演示如何使用
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"); try { User user = new User(); System.out.println("注入之前"+user); //User{id=null, username='null', password='null', email='null'} /* * 把所有请求的参数注入到user对象中 */ BeanUtils.populate(user,req.getParameterMap()); System.out.println("注入之后"+user); //User{id=null, username='test888', password='111111', email='test888@qq.com'} } catch (Exception e) { e.printStackTrace(); }
上面的这一句代码就已经把参数注入到user对象里面了
3)封装成webUtils工具类
package com.wufq.utils; import org.apache.commons.beanutils.BeanUtils; import java.util.Map; /** * @Description * @Author wufq * @Version * @Date 2021/7/2 16:06 */ public class WebUtils { /* * 把Map中的值注入到javabean中 * @param: req * @param: bean * @Return: void */ // public static void copyParamToBean(HttpServletRequest req,Object bean){ // public static void copyParamToBean(Map value, Object bean){ public static <T> T copyParamToBean(Map value, T bean){ try { //把所有请求的参数都注入到User对象中 /* * 这行代码的是关键,意思是req获取请求的参数已map的key、value形式存储然后传递给bean对象 * 但是如果HttpServletRequest req这种方式写的话,对web层耦合度高,但是对service层和dao层就不太适合 * 所以既然req.getParameterMap()是一个map集合,那么直接就可以把HttpServletRequest req写成Map value */ // BeanUtils.populate(bean,req.getParameterMap()); BeanUtils.populate(bean, value); } catch (Exception e) { e.printStackTrace(); } return bean; } }
4)修改UserServlet内注册成功、登录成功需要传入的user
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"); //调用WebUtils把请求注入到user对象中 User user = copyParamToBean(req.getParameterMap(),new User()); .... userService.registUser(user);//把user对象传入到registUser中 protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ // 1、获取请求的参数 String username = req.getParameter("username"); String password = req.getParameter("password"); //调用WebUtils把请求注入到user对象中 User user = copyParamToBean(req.getParameterMap(),new User()); // 2、调用userService.login()登录处理业务 //User loginUser = userService.login(new User(null, username, password, null)); User loginUser = userService.login(user);
第四阶段 使用EL表达式修改表单回显