Web-第二十一天 Web商城实战一【悟空教程】 今日内容介绍 用户管理:用户注册 用户管理:用户激活 用户管理:用户登录 用户管理:用户退出 用户管理:自动登录 用户管理:记住用户名 今日内容学习目标 JavaWeb知识巩固 参考: 创建数据库:(完成整个项目时,我们采用需要时再创建对应的表。) -- 创建数据库 drop database if exists `store_db`; create database `store_db`; -- 使用数据库 use store_db; 方式1:一个路径对应一个servlet 方式2:多个路径对应一个servlet,method请求参数与if语句进行分流 “方式2”的不足就是service()方法需要编写大量if语句。 方式3:多个路径对应一个servlet,编写BaseServlet,使用反射执行当前运行类的指定方法 方式4:完善BaseServlet,当前运行类的指定方法返回请求转发时jsp页面路径 步骤1:创建项目,并创建BaseServlet类 步骤2:编写BaseServlet实现类 1. 获得请求参数method,确定具体需要执行的方法名 2. 获得当前运行类需要执行的方法Method 3. 执行当前运行类对应的方法 4. 通过方法返回值确定请求转发jsp位置 public class BaseServlet extends HttpServlet { private static final long serialVersionUID = -3603954953627270784L; @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { //1 获得请求参数method String methodName = request.getParameter("method"); // * 默认方法名 if(methodName == null){ methodName = "execute"; } //2 获得当前运行类,需要指定的方法 Method method = this.getClass().getMethod(methodName, HttpServletRequest.class,HttpServletResponse.class); //3 执行方法 String jspPath = (String) method.invoke(this, request,response); //4 如果子类有返回值,将请求到指定的jsp页面 if(jspPath != null){ request.getRequestDispatcher(jspPath).forward(request, response); } } catch (Exception e) { // 异常处理:根据不同的异常,进行不同的处理 throw new RuntimeException(e); } } /** * 默认方法,用于子类复写 */ public String execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //NOOP (NO OPeration,无操作) return null; } } 步骤3:测试 servlet实现类 public class UserServlet extends BaseServlet { private static final long serialVersionUID = 1L; public void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("findAll"); } } web.xml配置 <servlet> <servlet-name>UserServlet</servlet-name> <servlet-class>cn.com.javahelp.store.web.servlet.UserServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UserServlet</servlet-name> <url-pattern>/UserServlet</url-pattern> </servlet-mapping> 测试路径 http://localhost:8080/store_v1.0/UserServlet?method=findAll 配置c3p0连接池, public class JdbcUtils{ //使用命名配置 private static ComboPooledDataSource dataSource = new ComboPooledDataSource("javahelp"); /** * 获得数据源(连接池) * @return */ public static DataSource getDataSource(){ return dataSource; } /** * 获得连接 * @return * @throws SQLException */ public static Connection getConnection() throws SQLException{ return dataSource.getConnection(); } } 导入c3p0-config.xml配置文件 <c3p0-config> <!-- 命名的配置 --> <named-config name="javahelp"> <!-- 连接数据库的4项基本参数 --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/store_db</property> <property name="user">root</property> <property name="password">1234</property> <!-- 如果池中数据连接不够时一次增长多少个 --> <property name="acquireIncrement">5</property> <!-- 初始化连接数 --> <property name="initialPoolSize">20</property> <!-- 最小连接受 --> <property name="minPoolSize">10</property> <!-- 最大连接数 --> <property name="maxPoolSize">40</property> <!-- -JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量 --> <property name="maxStatements">0</property> <!-- 连接池内单个连接所拥有的最大缓存statements数 --> <property name="maxStatementsPerConnection">5</property> </named-config> </c3p0-config> 对BeanUtils进一步封装,同时处理日期转换。 方式1:传递JavaBean实例,将数据封装到实例对象中。 /** * 将数据封装给JavaBean,支持时间类型转换 * 例如: * User user = new User(); * MyBeanUtils.populate( user , request.getParameterMap() ); * @param bean * @param properties */ public static void populate(Object bean, Map<String,String[]> properties){ try { //1 创建BeanUtils提供时间转换器 DateConverter dateConverter = new DateConverter(); //2 设置需要转换的格式 dateConverter.setPatterns(new String[]{"yyyy-MM-dd","yyyy-MM-dd HH:mm:ss"}); //3 注册转换器 ConvertUtils.register(dateConverter, java.util.Date.class); //4 封装数据 BeanUtils.populate(bean, properties); } catch (Exception e) { throw new RuntimeException(e); } } 方式2:传递JavaBean Class类型,通过反射进行实例化,然后封装数据 /** * 高级封装,不需要new javabean * 例如: * User user = MyBeanUtils.populate( User.class , request.getParameterMap() ); * @param beanClass * @param properties * @return */ public static <T> T populate(Class<T> beanClass, Map<String,String[]> properties){ try { //1 使用反射创建实例 T bean = beanClass.newInstance(); //2.1 创建BeanUtils提供时间转换器 DateConverter dateConverter = new DateConverter(); //2.2 设置需要转换的格式 dateConverter.setPatterns(new String[]{"yyyy-MM-dd","yyyy-MM-dd HH:mm:ss"}); //2.3 注册转换器 ConvertUtils.register(dateConverter, java.util.Date.class); //3 封装数据 BeanUtils.populate(bean, properties); return bean; } catch (Exception e) { throw new RuntimeException(e); } } public class UUIDUtils { /** * 获得32长度的UUID字符串 * @return */ public static String getUUID() { return UUID.randomUUID().toString().replace("-", ""); } /** * 获得64长度的UUID字符串 * @return */ public static String getUUID64() { return getUUID() + getUUID(); } } 步骤1:过滤器实现类 public class EncodingFilter implements Filter { public void init(FilterConfig fConfig) throws ServletException { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { //0 强转 HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; //1 设置编码 request.setCharacterEncoding("UTF-8"); //2 创建自定义request MyRequest myRequest = new MyRequest(request); //3 放行,使用自定义request chain.doFilter(myRequest, response); } public void destroy() { } } 步骤2:过滤器配置 <!-- 编码 --> <filter> <filter-name>EncodingFilter</filter-name> <filter-class>cn.com.javahelp.store.web.filter.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>EncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 步骤3:自定义request实现类,对获得请求参数方法进行处理 public class MyRequest extends HttpServletRequestWrapper { //是否已经被编码,默认false,没有被编码 private boolean encoded = false; public MyRequest(HttpServletRequest request) { super(request); } /** * 获得指定名称的第一个参数 */ @Override public String getParameter(String name) { String[] all = getParameterValues(name); if(all == null){ return null; } return all[0]; } /** * 获得指定名称的所有参数 */ @Override public String[] getParameterValues(String name) { return getParameterMap().get(name); } /** * 获得所有的内容,key:指定的名称;value:指定名称对象的所有值 */ @Override public Map<String,String[]> getParameterMap() { try { //1 获得原始数据 Map<String, String[]> map = super.getParameterMap(); //2 如果是get请求,存放栏目 if(!encoded){ if ("GET".equalsIgnoreCase(super.getMethod())) { //遍历map,并遍历数组值 for (Map.Entry<String, String[]> entry : map.entrySet()) { String[] allValue = entry.getValue(); for (int i = 0; i < allValue.length; i++) { String encoding = super.getCharacterEncoding(); if(encoding == null){ encoding = "UTF-8"; } allValue[i] = new String(allValue[i].getBytes("ISO-8859-1"), encoding); } } //修改标记,表示已经编码 encoded = true; } } return map; } catch (Exception e) { throw new RuntimeException(e); } } } 修改index.jsp页面,使其通过servlet访问jsp 步骤1:修改index.jsp <jsp:forward page="/IndexServlet"></jsp:forward> 相当于 <jsp:forward page="/IndexServlet?method=execute"></jsp:forward> 步骤2:编写servlet实现类 public class IndexServlet extends BaseServlet { private static final long serialVersionUID = 1L; public String execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { return "/jsp/index.jsp"; } } 步骤3:web.xml indexServlet配置 <servlet> <servlet-name>IndexServlet</servlet-name> <servlet-class>cn.com.javahelp.store.web.servlet.IndexServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>IndexServlet</servlet-name> <url-pattern>/IndexServlet</url-pattern> </servlet-mapping> 步骤1:创建表,并初始化数据 -- 1.1 创建用户表 CREATE TABLE `user` ( `uid` varchar(32) NOT NULL, `username` varchar(20) DEFAULT NULL, #用户名 `password` varchar(20) DEFAULT NULL, #密码 `name` varchar(20) DEFAULT NULL, #昵称 `email` varchar(30) DEFAULT NULL, #电子邮箱 `telephone` varchar(20) DEFAULT NULL, #电话 `birthday` date DEFAULT NULL, #生日 `sex` varchar(10) DEFAULT NULL, #性别 `state` int(11) DEFAULT 0, #状态:0=未激活,1=已激活 `code` varchar(64) DEFAULT NULL, #激活码 PRIMARY KEY (`uid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 1.2 初始化用户默认数据 INSERT INTO `user` VALUES ('373eb242933b4f5ca3bd43503c34668b','ccc','ccc','aaa','bbb@store.com','15723689921','2015-11-04','男',0,'9782f3e837ff422b9aee8b6381ccf927bdd9d2ced10d48f4ba4b9f187edf7738'),('3ca76a75e4f64db2bacd0974acc7c897','bb','bb','张三','bbb@store.com','15723689921','1990-02-01','男',0,'1258e96181a9457987928954825189000bae305094a042d6bd9d2d35674684e6'),('62145f6e66ea4f5cbe7b6f6b954917d3','cc','cc','张三','bbb@store.com','15723689921','2015-11-03','男',0,'19f100aa81184c03951c4b840a725b6a98097aa1106a4a38ba1c29f1a496c231'),('c95b15a864334adab3d5bb6604c6e1fc','bbb','bbb','老王','bbb@store.com','15712344823','2000-02-01','男',0,'71a3a933353347a4bcacff699e6baa9c950a02f6b84e4f6fb8404ca06febfd6f'),('f55b7d3a352a4f0782c910b2c70f1ea4','aaa','aaa','小王','aaa@store.com','15712344823','2000-02-01','男',1,NULL); 步骤2:创建JavaBean public class User { private String uid; private String username; private String password; private String name; private String email; private String telephone; private Date birthday; private String sex; private int state; private String code; 步骤3:编写dao接口,及实现类 /** * 用户模块的DAO层的接口 */ public interface UserDao { } /** * 用户模块的DAO层的实现类 */ public class UserDaoImpl implements UserDao { } 步骤4:编写service接口,及实现类 /** * 用户模块的Service层的接口 */ public interface UserService { } /** * 用户模块的Service层的实现类 */ public class UserServiceImpl implements UserService { } 步骤5:编写servlet(测试BaseServlet已经编写) public class UserServlet extends BaseServlet { private static final long serialVersionUID = 1L; public void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("findAll"); } } <servlet> <servlet-name>UserServlet</servlet-name> <servlet-class>cn.com.javahelp.store.web.servlet.UserServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UserServlet</servlet-name> <url-pattern>/userServlet</url-pattern> </servlet-mapping> 步骤1:修改 /store_v1.0/WebContent/jsp/index.jsp 页面 <a href="${pageContext.request.contextPath}/UserServlet?method=registUI">注册</a> 步骤2:修改UserServlet,添加registUI()方法 //注册页面 public String registUI(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { return "/jsp/register.jsp"; } 1. 完善regist.jsp表单,确定表单元素有name属性 2. 在注册页面输入信息,点击注册,提交到UserServlet的regist()方法进行处理 3. servlet调用service的 regist(user)进行用户注册操作 4. service调用dao的save(user) 将用户保存到数据库。 步骤1:完善表单,确定表单元素的name属性 <form action="${pageContext.request.contextPath}/UserServlet?method=regist" method="post" …> <input type="text" name="username" placeholder="请输入用户名"> <input type="password"name="password" placeholder="请输入密码"> <input type="password" name="confirmpwd" placeholder="请输入确认密码"> <input type="email" name="email" placeholder="Email"> <input type="text" name="name" placeholder="请输入姓名"> <input type="radio" name="sex" value="男"> 男 <input type="radio" name="sex" value="女"> 女 <input type="date" name="birthday" > 步骤2:修改UserServlet,提供regist(request,response)方法 public String regist(HttpServletRequest request, HttpServletResponse response)throws Exception { //1 获得数据并封装 User user = MyBeanUtils.populate(User.class, request.getParameterMap()); //1.1 处理服务器自动生成 user.setUid(UUIDUtils.getUUID()); user.setCode(UUIDUtils.getUUID64());//激活码 user.setState(0);//0=未激活 //2 处理 UserService userService = new UserServiceImpl(); userService.regist(user); //3 成功提示 request.setAttribute("msg", "注册成功,请邮件激活后请登录"); //注册成功登录 return "/jsp/login.jsp"; } 步骤3:修改UserService,提供regist(user)方法进行注册 //接口 /** * 注册 * @param user */ void regist(User user) throws SQLException; //实现类 @Override public void regist(User user) throws SQLException{ //保存用户 userDao.save(user); //发送邮件 } 步骤4:修改UserDao,提供save(user)方法进行用户信息的保存。 //接口 /** * 保存用户 * @param user * @throws SQLException */ void save(User user) throws SQLException; //实现类 public void save(User user) throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "insert into user(uid,username,password, name,email,telephone, birthday,sex,state, code) values (?,?,?, ?,?,?, ?,?,?, ?)"; Object[] params = { user.getUid(), user.getUsername(), user.getPassword(), user.getName(), user.getEmail(),user.getTelephone(), user.getBirthday(), user.getSex(), user.getState(), user.getCode() }; queryRunner.update(sql, params); } 步骤5:修改登录 /jsp/login.jsp页面,添加提示信息 邮件协议: POP3协议:接收邮件服务器(邮局协议)端口110 SMTP协议:发送邮件服务器(简单邮件传输协议),端口25 1. 注册用户保存到数据库后发生激活邮箱 2. 创建会话,确定连接邮箱服务器的地址 3. 编写消息,确定需要发送的内容 4. 发送消息 步骤1:确定导入mail.jar 步骤2:修改service,发送邮件 @Override public void regist(User user) throws SQLException{ //保存用户 userDao.save(user); //发送邮件 MailUtils.sendMail(user.getEmail(), user.getCode()); } 步骤3:编写MailUtils工具类发送邮件,使用外网模拟。 /** * 外网邮件发送 * @param to * @param code */ public static void sendMail(String to,String code){ // Session对象: Properties props = new Properties(); props.setProperty("mail.host", "smtp.163.com"); props.setProperty("mail.smtp.auth", "true"); Session session = Session.getInstance(props, new Authenticator() { @Override public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("******@163.com", "1qaz2wsx"); } }); // Message对象: Message message = new MimeMessage(session); // 设置发件人: try { message.setFrom(new InternetAddress("****@163.com")); // 设置收件人: message.addRecipient(RecipientType.TO, new InternetAddress("***@126.com")); // 设置主题: message.setSubject("来自购物天堂STORE的激活邮件"); // 设置内容: String url = "http://localhost:8080/store_v1.0/UserServlet?method=active&code="+code; message.setContent("<h1>来自购物天堂STORE的激活邮件!激活请点击以下链接!</h1><h3><a href='"+url+"'>"+url+"</a></h3>","text/html;charset=UTF-8"); // Transport对象: Transport.send(message); } catch (AddressException e) { e.printStackTrace(); } catch (MessagingException e) { e.printStackTrace(); } } 步骤4:如果不能使用外网,可以搭建本地邮件服务器(可选) /** * 本地邮件发送 * @param to * @param code */ public static void sendMail2(String to,String code){ // Session对象: Properties props = new Properties(); // props.setProperty("smtp.host", "localhost"); Session session = Session.getInstance(props, new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication("service@store.com", "111"); } }); // Message对象: Message message = new MimeMessage(session); // 设置发件人: try { message.setFrom(new InternetAddress("service@store.com")); // 设置收件人: message.addRecipient(RecipientType.TO, new InternetAddress(to)); // 设置主题: message.setSubject("来自购物天堂STORE的激活邮件"); // 设置内容: String url = "http://localhost:8080/store_v1.0/UserServlet?method=active&code="+code; message.setContent("<h1>来自购物天堂STORE的激活邮件!激活请点击以下链接!</h1><h3><a href='"+url+"'>"+url+"</a></h3>","text/html;charset=UTF-8"); // Transport对象: Transport.send(message); } catch (AddressException e) { e.printStackTrace(); } catch (MessagingException e) { e.printStackTrace(); } } 1.通过FoxMail接收邮件,点击邮件内连接 2.编写UserServlet的active方法,服务器获得用户激活码,并进行激活 3.编写UserService的activeUser方法,通过激活码,激活用户 * 激活成功,将激活码制空。 * 如果激活码不可用,抛异常 步骤1:通过邮箱点击激活路径 步骤2:修改UserServlet,添加active方法进行用户激活 //用户激活 public String active(HttpServletRequest request, HttpServletResponse response) throws Exception { try { // 1 获得激活码 String code = request.getParameter("code"); //2 用户激活 UserService userService = new UserServiceImpl(); userService.activeUser(code); //3 成功提示 request.setAttribute("msg", "激活成功,请登录"); } catch (Exception e) { e.printStackTrace(); request.setAttribute("msg", e.getMessage()); } return "/jsp/login.jsp"; } 步骤3:修改UserService,添加activeUser ()方法 //接口 /** * 激活用户 * @param code */ void activeUser(String code) throws SQLException; //实现类 public void activeUser(String code) throws SQLException{ //1 通过激活码查询用户 User existUser = userDao.findByCode(code); if(existUser == null){ //自定义异常 throw new RuntimeException("用户激活码无效,请重试或重新发送激活邮件"); } //2 更新用户信息 existUser.setState(1); existUser.setCode(null); userDao.update(existUser); } 步骤4:修改UserDao,添加findByCode()和update() 两个方法 //接口 /** * 通过激活码查询用户 * @param code * @return */ User findByCode(String code)throws SQLException; /** * 更新用户信息 * @param existUser */ void update(User user)throws SQLException; //实现类 @Override public User findByCode(String code) throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from user where code = ?"; User existUser = queryRunner.query(sql, new BeanHandler<User>(User.class), code); return existUser; } @Override public void update(User user) throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "update user set username=?,password=?, name=?,email=?,telephone=?, birthday=?,sex=?,state=?, code=? where uid=?"; Object[] params = { user.getUsername(), user.getPassword(), user.getName(), user.getEmail(),user.getTelephone(), user.getBirthday(), user.getSex(), user.getState(), user.getCode() ,user.getUid()}; queryRunner.update(sql, params); } 步骤1:修改/store_v1.0/WebContent/jsp/index.jsp 页面 <a href="${pageContext.request.contextPath}/UserServlet?method=loginUI">登录</a> 步骤2:修改servlet,添加loginUI方法 //登录页面 public String loginUI(HttpServletRequest request, HttpServletResponse response) throws Exception { return "/jsp/login.jsp"; } 1. 完善login.jsp表单 2. 在登录页面输入用户名和密码,点击登录,发送请求到UserServlet 3. 获得用户名和密码,通过用户名和密码查询用户 4. 如果用户存在表示登录成功,将用户信息保存到session,并重定向到首页 5. 如果用户不存在,给用户错误提示,并重新登录 步骤1:完善表单 <form action="${pageContext.request.contextPath}/UserServlet?method=login" method="post"> <input type="text" name="username" placeholder="请输入用户名"> <input type="password" name="password" placeholder="请输入密码"> 步骤2:修改UserServlet,添加login方法 //登录 public String login(HttpServletRequest request, HttpServletResponse response) throws Exception { //1 封装数据 User user= MyBeanUtils.populate(User.class, request.getParameterMap()); //2 通知service进行登录 UserService userService = new UserServiceImpl(); User loginUser = userService.login(user); //3 成功处理 if(loginUser != null){ //3.1 session作用域记录登录状态 request.getSession().setAttribute("loginUser", loginUser); //3.2 重定向到首页 response.sendRedirect(request.getContextPath() + "/"); //3.3 不使用baseServlet的请求转发 return null; } //4 错误处理 // 4.1 request作用域记录错误信息 request.setAttribute("msg", "用户名或密码不匹配或未激活"); // 4.2 请求转发到登录页 return "/jsp/login.jsp"; } 步骤3:修改UserService,添加login()方法 //接口 /** * 登录 * @param user * @return */ User login(User user)throws SQLException; //实现类 @Override public User login(User user) throws SQLException{ return userDao.find(user.getUsername() ,user.getPassword()); } 步骤4:修改UserDao,添加find() 方法 //接口 /** * 通过用户名和密码查询用户 * @param username * @param password * @return */ User find(String username, String password)throws SQLException; //实现类 public User find(String username, String password) throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from user where username = ? and password = ?"; User existUser = queryRunner.query(sql, new BeanHandler<User>(User.class), username,password); return existUser; } 步骤5:完善首页,根据是否登录,实现不同的程序入口。 <%@taglib uri="http://java./jsp/jstl/core" prefix="c" %> <c:if test="${empty loginUser }"> <li><a href="${pageContext.request.contextPath}/UserServlet?method=loginUI">登录</a></li> <li><a href="${pageContext.request.contextPath}/UserServlet?method=registUI">注册</a></li> </c:if> <li><a href="${pageContext.request.contextPath}/jsp/cart.jsp">购物车</a></li> <c:if test="${not empty loginUser }"> 欢迎:${loginUser.name} , <li><a href="${pageContext.request.contextPath}/jsp/order_list.jsp">我的订单</a></li> <li><a href="${pageContext.request.contextPath}/jsp/order_list.jsp">退出</a></li> </c:if> 在用户登录时,点击退出,发送请求到服务器 将session保存用户信息移除,重定向到首页 步骤1:确定入口 <li><a href="${pageContext.request.contextPath}/UserServlet?method=logout">退出</a></li> 步骤2:修改UserServlet,添加logout()方法 //退出 public String logout(HttpServletRequest request, HttpServletResponse response) throws Exception { //1 将session用户状态信息移除 request.getSession().removeAttribute("loginUser"); //2 重定向到首页 response.sendRedirect(request.getContextPath() + "/UserServlet?method=loginUI"); //3.3 不使用baseServlet的请求转发 return null; } 登录成功后,如果用户勾选自动登录,使用cookie将用户信息响应给浏览器 下次请求时,使用过滤器filter拦截器请求,获得用户信息,进行自动登录 步骤1:确定登录表单 <input type="checkbox" name="autoLogin" value="1"> 自动登录 步骤2:修改UserServlet,修改login()方法,判断是否勾选自动登录。如果勾选,使用cookie记录用户信息;如果用登录时没有勾选复选框,将删除之前自动登录cookie。 //3 成功处理 if(loginUser != null){ //#1 自动登录start String autoLogin = request.getParameter("autoLogin"); if("1".equals(autoLogin)){ // 如果勾选发送cookie3 Cookie autoLoginCookie = new Cookie("autoLoginCookie", user.getUsername() + "@" + user.getPassword()); autoLoginCookie.setPath("/"); autoLoginCookie.setMaxAge(60*60*24*7); response.addCookie(autoLoginCookie); } else { // 删除cookie Cookie autoLoginCookie = new Cookie("autoLoginCookie", ""); autoLoginCookie.setPath("/"); autoLoginCookie.setMaxAge(0); response.addCookie(autoLoginCookie); } 步骤3:编写CookieUtils工具类,用于获得指定名称的cookie public class CookieUtils { /** * 获得指定cookie * @param allCookie * @param cookieName * @return */ public static Cookie getCookie(Cookie[] allCookie , String cookieName){ if(cookieName == null){ return null; } if(allCookie != null){ for (Cookie c : allCookie) { if(cookieName.equals(c.getName())){ return c; } } } return null; } } 步骤4:编写LoginFilter 过滤器 public class LoginFilter implements Filter{ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { //0 强转 HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 如果是登录页直接放行 String servletPath = request.getServletPath(); if(servletPath.startsWith("/UserServlet")){ String method = request.getParameter("method"); if("loginUI".equals(method)){ chain.doFilter(request, response); return; } } //1 用户登录信息 User loginUser = (User) request.getSession().getAttribute("loginUser"); //2 如果已经登录,放行,不需要自动登录 if(loginUser != null){ chain.doFilter(request, response); return; //程序结束 } //3 获得 自动登录 cookie信息 Cookie userCookie = CookieUtils.findCookie(request.getCookies() , "autoLoginCookie" ); //4 判断自动登录cookie是否存在,如果没有cookie,不需要自动 if(userCookie == null){ chain.doFilter(request, response); return; } //5 通过用户cookie中记录信息,查询用户 // 5.1 获得用户信息 String[] u = userCookie.getValue().split("@"); String username = u[0]; String password = u[1]; User user = new User(username, password); try { // 5.2 执行登录 UserService userServic = new UserServiceImpl(); loginUser = userServic.login(user); //6 如果没有查询(修改密码 if (loginUser == null) { chain.doFilter(request, response); return; } // 7 自动登录 request.getSession().setAttribute("loginUser", loginUser); //放行 chain.doFilter(request, response); } catch (Exception e) { System.out.println("自动登录异常,自动忽略"); } } 步骤5:web.xml 配置 <filter> <filter-name>LoginFilter</filter-name> <filter-class>cn.com.javahelp.store.web.filter.LoginFilter</filter-class> </filter> <filter-mapping> <filter-name>LoginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> 步骤6:当用户访问登录页时,不进行自动登录,但登录复选框需要勾选 <input type="checkbox" name="autoLogin" value="1" ${not empty cookie.autoLoginCookie? "checked='checked'" : ""} > 自动登录 登录成功后,判断是否勾选记住用户名 如果已经勾选,使用cookie记录用户名 在访问登录页面时,使用el回显用户名 步骤1:确定页面 <input type="checkbox" name="rememberme" value="1"> 记住用户名 步骤2:修改login()方法,如果已经勾选,使用cookie 记录用户名 //#2 记住用户名 start String rememberme = request.getParameter("rememberme"); if("1".equals(rememberme)){ Cookie remembermeCookie = new Cookie("remembermeCookie", user.getUsername()); remembermeCookie.setPath("/"); remembermeCookie.setMaxAge(60*60*24*7); response.addCookie(remembermeCookie); } //省略cookie的删除 //#2 记住用户名 end 步骤3:修改login.jsp页面,如果有记住用户名cookie使用el表达式进行显示 <input type="text" name="username" placeholder="请输入用户名" value="${cookie.remembermeCookie.value}"> ... <input type="checkbox" name="rememberme" value="1" ${not empty cookie.remembermeCookie? "checked='checked'" : ""}> 记住用户名 步骤1:将导航条提取到header.jsp页面,摘要如下: <%@taglib uri="http://java./jsp/jstl/core" prefix="c" %> <!-- 时间:2015-12-30 描述:菜单栏 --> <c:if test="${empty loginUser }"> <li><a href="${pageContext.request.contextPath}/UserServlet?method=loginUI">登录</a></li> <li><a href="${pageContext.request.contextPath}/UserServlet?method=registUI">注册</a></li> </c:if> <li><a href="${pageContext.request.contextPath}/jsp/cart.jsp">购物车</a></li> <c:if test="${not empty loginUser }"> 欢迎:${loginUser.name} , <li><a href="${pageContext.request.contextPath}/jsp/order_list.jsp">我的订单</a></li> <li><a href="${pageContext.request.contextPath}/UserServlet?method=logout">退出</a></li> </c:if> <!-- 描述:导航条 --> <a href="${pageContext.request.contextPath}">首页</a> 步骤2:其他所有的前台页面,都静态包含header.jsp页面 <%--包含导航条 --%> <%@include file="/jsp/header.jsp" %> 1. 用户名文本框失去焦点触发JS函数 2. 使用AJAX发送异步请求 3. 获得服务器响应的数据,并处理,将结果显示在文本框后面的span中 步骤1:确定html页面 <input type="text" id="username" placeholder="请输入用户名"> <span id="s1"></span> <input type="submit" id="regBut" value="注册" …/> 步骤2:给username文本框绑定事件,blur失去焦点触发js <script type="text/javascript"> $(function(){ $("#username").blur(function(){ // 获得文本框的值: var val = $(this).val(); // 异步发送数据: if(val != ""){ var url = "${ pageContext.request.contextPath }/UserServlet"; var params = {"method":"checkUsername","username":val}; $.post(url,params,function(data){ if(data == 1){ $("#s1").html("用户名可以使用").css("color","#0f0"); $("#regBut").attr("disabled",false); }else if(data == 2){ $("#s1").html("用户名已经被注册").css("color","#f00"); $("#regBut").attr("disabled",true); } }); } }); }); </script> 步骤3:修改UserServlet,添加checkUsername()方法 // ajax检查用户名 public void checkUsername(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 接收文本框的值: String username = request.getParameter("username"); // 调用业务层查询: UserService userService = new UserServiceImpl(); User existUser = userService.findByUsername(username); // 判断: if(existUser == null){ // 用户名没有使用 response.getWriter().println(1); }else{ // 用户名已经被使用 response.getWriter().println(2); } } 步骤4:修改service,添加 findByUsername()方法 //接口 public interface UserService { /** * 通过用户名查询用户 * @param username * @return */ User findByUsername(String username) throws SQLException; } //实现类 public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); @Override public User findByUsername(String username) throws SQLException { return userDao.findByUsername(username); } } 步骤5:修改dao,添加findByUsername()方法 //接口 public interface UserDao { /** * 通过用户名查询用户 * @param username * @return * @throws SQLException */ User findByUsername(String username) throws SQLException; } //实现类 public class UserDaoImpl implements UserDao { @Override public User findByUsername(String username) throws SQLException { QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource()); String sql = "select * from user where username = ?"; User existUser = queryRunner.query(sql, new BeanHandler<User>(User.class), username); return existUser; } } |
|