Web-第二十一天 Web商城实战一【悟空教程】

Web-第二十一天 Web商城实战一【悟空教程】

Web商城实战一

今日内容介绍

  • 用户管理:用户注册
  • 用户管理:用户激活
  • 用户管理:用户登录
  • 用户管理:用户退出
  • 用户管理:自动登录
  • 用户管理:记住用户名

今日内容学习目标

  • JavaWeb知识巩固

第1章 网络商城实战

1.1 数据库分析与设计

  • 参考:
  • 创建数据库:(完成整个项目时,我们采用需要时再创建对应的表。)

-- 创建数据库

drop database if exists `store_db`;

create database `store_db`;

-- 使用数据库

use store_db;

1.2 通用Servlet

1.2.1 分析

  • 方式1:一个路径对应一个servlet
  • 方式2:多个路径对应一个servlet,method请求参数与if语句进行分流

“方式2”的不足就是service()方法需要编写大量if语句。

  • 方式3:多个路径对应一个servlet,编写BaseServlet,使用反射执行当前运行类的指定方法
  • 方式4:完善BaseServlet,当前运行类的指定方法返回请求转发时jsp页面路径

1.2.2 实现

  • 步骤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

第2章 环境搭建

2.1 目录结构

2.2 导入jar包

2.3 工具类

2.3.1 JdbcUtils

  • 配置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>

2.3.2 MyBeanUtils

  • 对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);

}

}

2.3.3 UUIDUtils

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();

}

}

2.4 编码过滤器

  • 步骤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);

}

}

}

2.5 导入JSP页面

  • 修改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>

第3章 前台用户模块

3.1 编写流程

  • 步骤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>

3.2 功能:用户注册

3.2.1 显示注册表单

  • 步骤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";

}

3.2.2 用户注册

3.2.2.1 分析

3.2.2.2 编写步骤

1. 完善regist.jsp表单,确定表单元素有name属性

2. 在注册页面输入信息,点击注册,提交到UserServlet的regist()方法进行处理

3. servlet调用service的 regist(user)进行用户注册操作

4. service调用dao的save(user) 将用户保存到数据库。

3.2.2.3 代码实现

  • 步骤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页面,添加提示信息

3.2.3 发送激活邮件

3.2.3.1 邮件概述

  • 邮件协议:
    • POP3协议:接收邮件服务器(邮局协议)端口110
    • SMTP协议:发送邮件服务器(简单邮件传输协议),端口25

3.2.3.2 分析

3.2.3.3 编写步骤

1. 注册用户保存到数据库后发生激活邮箱

2. 创建会话,确定连接邮箱服务器的地址

3. 编写消息,确定需要发送的内容

4. 发送消息

3.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();

}

}

3.3 功能:用户激活

3.3.1 分析

3.3.2 编写步骤

1.通过FoxMail接收邮件,点击邮件内连接

2.编写UserServlet的active方法,服务器获得用户激活码,并进行激活

3.编写UserService的activeUser方法,通过激活码,激活用户

* 激活成功,将激活码制空。

* 如果激活码不可用,抛异常

3.3.3 代码实现

  • 步骤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);

}

3.4 功能:用户登录

3.4.1 显示登录表单

  • 步骤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";

}

3.4.2 登录功能

3.4.2.1 分析

3.4.2.2 编写步骤

1. 完善login.jsp表单

2. 在登录页面输入用户名和密码,点击登录,发送请求到UserServlet

3. 获得用户名和密码,通过用户名和密码查询用户

4. 如果用户存在表示登录成功,将用户信息保存到session,并重定向到首页

5. 如果用户不存在,给用户错误提示,并重新登录

3.4.2.3 代码实现

  • 步骤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.sun.com/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>

3.5 功能:用户退出

3.5.1 分析

3.5.2 编写步骤

在用户登录时,点击退出,发送请求到服务器

将session保存用户信息移除,重定向到首页

3.5.3 代码实现

  • 步骤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;

}

第4章 作业

4.1 功能:自动登录

4.1.1 分析

4.1.2 编写步骤

登录成功后,如果用户勾选自动登录,使用cookie将用户信息响应给浏览器

下次请求时,使用过滤器filter拦截器请求,获得用户信息,进行自动登录

4.1.3 代码实现

  • 步骤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'" : ""} > 自动登录

4.2 功能:记住用户名

4.2.1 分析

4.2.2 编写步骤

登录成功后,判断是否勾选记住用户名

如果已经勾选,使用cookie记录用户名

在访问登录页面时,使用el回显用户名

4.2.3 代码实现

  • 步骤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'" : ""}> 记住用户名

4.3 功能:完善所有jsp页面,提供header

  • 步骤1:将导航条提取到header.jsp页面,摘要如下:

<%@taglib uri="http://java.sun.com/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" %>

4.4 功能:异步校验用户名是否存在(自己完成)

4.4.1 分析

4.4.2 编写步骤

1. 用户名文本框失去焦点触发JS函数

2. 使用AJAX发送异步请求

3. 获得服务器响应的数据,并处理,将结果显示在文本框后面的span中

4.4.3 代码实现

  • 步骤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;

}

}

原文发布于微信公众号 - Java帮帮(javahelp)

原文发表时间:2018-07-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java成神之路

20180831_jar包冲突2_天安微信httpclient冲突

在本地用tomcat跑时,是正常的。但是在服务器上用weblogic跑时,却报了这个异常。

1861
来自专栏Kubernetes

原 荐 Kubernetes Resourc

更多关于kubernetes的深入文章,请看我csdn或者oschina的博客主页。 ResoureQuota介绍 关于ResoureQuota和Resourc...

5209
来自专栏Java帮帮-微信公众号-技术文章全总结

Web-第二十三天 Web商城实战三【悟空教程】

<a href="${pageContext.request.contextPath}/OrderServlet?method=findByUid">我的订单<...

1751
来自专栏Fred Liang

[翻译]构建带 Subscriptions 的 graphql golang 后端

GraphQL提供了一种灵活而有效的方式来查询服务器中的数据。 它正在成为设计后端的流行技术,通常会替换或封装一些不灵活的REST API,并让客户负责决定他们...

2013
来自专栏Google Dart

Dart 服务端开发 文件上传 原

1092
来自专栏草根专栏

从头编写 asp.net core 2.0 web api 基础框架 (3)

Github源码地址:https://github.com/solenovex/Building-asp.net-core-2-web-api-starter-...

4917
来自专栏Kubernetes

原 深入分析Kubernetes Sche

1964
来自专栏安恒网络空间安全讲武堂

[HCTF] share write up

从http://share.2018.hctf.io/robots.txt中获取到题目部分源码

972
来自专栏xingoo, 一个梦想做发明家的程序员

开启服务和停止服务

Start函数用于开启服务 1 初始化状态变量 2 创建监听套接字 3 加载使用扩展API函数 4 创建完成端口对象 5 建立监听套接字和完成端口对象间的关联 ...

2808
来自专栏分布式系统进阶

KafkaController分析4-Partition选主

601

扫码关注云+社区

领取腾讯云代金券