前言:这是一篇新手在浏览了别的大神的作品后总结出的项目,建议大家都动手实践一下。需要对JSP+Servlet+JSTL+mysql+jdbc技术有了解,会使用juint测试,如果有能力的可以在本篇基础上使用Ajax、jQuery、json和JavaScript做出更好的界面和效果,再者可使用工厂模式来完成。(以后学习后会在本文结尾进行技术的更新)
1.搭建开发环境
要引入的jar包有:
可以去我的资源里下载(本来想免费提供,发现csdn不能免费上传)、也可以到我的源码内获取
2.分层架构的代码编写
分层架构的代码是按照【域模型层(domain)】—【数据访问层(dao、dao.impl)】—【业务处理层(service、service.impl)】—【表现层(web.controller、web.UI、web.filter、web.listener)】—【工具类(util)】—【测试类(junit.test)】的顺序编写的。
一、域模型层(domain层的开发)
User用户实体类代码如下:
package me.TiHom.domain;
import java.util.Date;
/**
* 用户实体类
*/
public class User {
private String id; //用户ID
private String username; //用户的用户名
private String password; //用户的密码
private String email; //用户的邮箱
private Date birthday; //用户的生日
private String nickname; //用户的昵称
public String getId() {
return id;
}
public void setId(String 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;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
}
二、介于要与数据库连接,我们需要先编写数据库连接类JdbcUtils,因为只是简单案例,这里就采用最普通的jdbc连接方法而不采用连接池。
对于我这个新手,在一开始写的时候总是忘了导包,记住要把mysql的驱动包放到web包的WEB-INF下,否则虽然在main中是显示连接成功但是在web应用时实际是没连接上的
JdbcUtils数据库连接类代码如下:(写的有点粗糙,以后的项目会改进写法)
package me.TiHom.web.utils;
import java.sql.*;
/**
* 数据库连接类
*/
public class JdbcUtils {
public static final String driver = "com.mysql.jdbc.Driver";
public static final String URL = "jdbc:mysql://127.0.0.1:3306/这是你表的名字";
public static final String USERNAME = "root";
public static final String PASSWORD = "这是你的密码";
public static Connection connection = null;
static {
try {
/* 加载驱动 */
Class.forName(driver);
/* 使用驱动类连接数据库 */
connection = DriverManager.getConnection(URL,USERNAME,PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
/* 方便其他包调用来连接数据库 */
public static Connection getConnection(){
return connection;
}
/* 方便其他包直接调用释放连接资源 */
public static void releaseJdbc(Statement statement, ResultSet resultSet){
try {
if(statement!=null){
statement.close();
}
if(resultSet!=null){
resultSet.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/* 测试数据库的连接是否成功 */
public static void main(String[] args) {
try {
Connection connection = JdbcUtils.getConnection();
if(connection != null){
System.out.println("数据库连接正常!");
}else {
System.out.println("数据库连接异常!");
}
}catch (Exception ex){
ex.printStackTrace();
}
}
}
三、数据访问层的开发(与数据库交互dao、dao.impl)
对于Dao层的作用,建议观看我之前总结过的MVC模式小结。总结不好之处欢迎指出。
我的习惯是在dao上实现接口;在dao.impl上写实现接口的类,这里面包含对数据库的CURD(增删改查)操作和数据业务逻辑处理。
UserDao接口类代码如下:
package me.TiHom.dao;
import me.TiHom.domain.User;
public interface UserDao {
/**
* 添加用户
* @param user
*/
void add(User user);
/**
* 根据用户名和密码来查找用户
* @param username
* @param password
* @return 查到的用户
*/
User find(String username,String password);
/**
* 根据用户名来查找用户
* @param username
* @return 查找到的用户
*/
boolean find(String username);
}
UserDaoJdbcImpl接口实现类的代码如下:
package me.TiHom.dao.impl;
import me.TiHom.web.utils.JdbcUtils;
import me.TiHom.dao.UserDao;
import me.TiHom.domain.User;
import me.TiHom.exception.DaoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
* UserDao接口的实现类
*/
public class UserDaoJdbcImpl implements UserDao{
@Override
public void add(User user){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "insert into users(id,username,password,email,birthday,nickname) values(?,?,?,?,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1,user.getId());
ps.setString(2,user.getUsername());
ps.setString(3,user.getPassword());
ps.setString(4,user.getEmail());
ps.setDate(5,new java.sql.Date(user.getBirthday().getTime()));
ps.setString(6,user.getNickname());
int num = ps.executeUpdate();
if(num < 1){
throw new RuntimeException("注册用户失败!!");
}
} catch (Exception e) {
/*
我们的处理方法——你这个有程序有异常,你拿到这个异常,怎么做呢?就看异常你希不希望上一层程序处理?
如果你不希望上一层程序处理,免得给上一层程序带来麻烦,就转为运行时异常抛出去,
如果你希望上一层程序处理,就转为编译时异常直接往上抛出去。
*/
throw new DaoException(e);
} finally {
//释放资源
JdbcUtils.releaseJdbc(ps,rs);
}
}
@Override
public User find(String username,String password){
Connection conn = null;
//PreparedStatement防止sql注入
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from users where username=? and password=?";
ps = conn.prepareStatement(sql);
ps.setString(1,username);
ps.setString(2,password);
rs = ps.executeQuery();
while(rs.next()){
User user = new User();
user.setId(rs.getString("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
user.setNickname(rs.getString("nickname"));
return user;
}
return null;
} catch (Exception e) {
//异常直接往上面抛,除了给上层带来麻烦,没有任何好处,所以可将异常转型然后往业务层抛
throw new DaoException(e);
} finally {
JdbcUtils.releaseJdbc(ps,rs);
}
}
@Override
public boolean find(String username){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = "select * from users where username=?";
ps = conn.prepareStatement(sql);
ps.setString(1,username);
rs = ps.executeQuery();
while(rs.next()){
return true;
}
return false;
} catch (Exception e) {
throw new DaoException(e);
} finally {
JdbcUtils.releaseJdbc(ps,rs);
}
}
}
这里可能会对我抛异常这里有疑惑,因为我抛的是自定义的异常,在参考了别的博主的文章后得到的解释:
1.问:在实际开发过程中,经常自定义异常的作用?
a.最大的好处是我把自定义异常抛出去的时候,人家收到这个异常,一看到这个异常的名字就可以知道到底是哪一层出现的问题,就可以快速定位到这一层来找问题,最好每一层都有个自定义异常
b.你这个程序有异常,你拿到这个异常,怎么做呢?就看异常你希不希望上一层程序去处理?如果你不希望上一层程序处理,免得给上一层程序带来麻烦,就转为运行时异常抛出,如果你希望上一层程序处理就转为编译时异常直接往上抛出。
2.问:Statement和PrepareStatement的区别:
a.PrepareStatement是Statement的子类
b.PrepareStatement可以防止sql注入的问题
c.PrepareStatement会对sql语句进行预编译,以减轻数据库服务器的压力
3.子类在覆盖父类的方法时,不能抛出比父类更多的异常。
我看了一个例子描述的挺好的,就是比如你爸爸做了坏事,他生的孩子应该尽量不要比他爸爸更坏,应该向好的发展。
四、service层的开发(service层对web层提供所有的业务服务)
UserService的代码如下:
package me.TiHom.web.service;
import me.TiHom.domain.User;
import me.TiHom.exception.UserExistException;
public interface UserService {
/**
* 提供注册服务
* @param user
* @throws UserExistException
*/
void register(User user) throws UserExistException;
/**
* 提供登录服务
* @param username
* @param password
* @return
*/
User login(String username,String password);
}
BusinessServiceImpl接口实现类的代码如下:
package me.TiHom.web.service.impl;
import me.TiHom.web.service.UserService;
import me.TiHom.web.utils.ServiceUtils;
import me.TiHom.dao.UserDao;
import me.TiHom.domain.User;
import me.TiHom.exception.UserExistException;
import factory.DaoFactory;
public class BusinessServiceImpl implements UserService {
/*
* 业务逻辑层和数据访问层要解耦——希望底层Dao层代码换了,业务逻辑层的代码一行不改,这时要用到工厂设计模式
* 要解耦,由两种方法:
* 1.工厂模式
* 2.spring
*/
private UserDao dao = DaoFactory.getInstance().createDao(UserDao.class);
@Override
//对web层提供注册服务
public void register(User user) throws UserExistException{
//先判断当前要注册的用户是否存在
if(dao.find(user.getUsername())){
/*
* service层是由web层来调用的
* 发现当前要注册的用户已存在,要提醒给web层,web层给用户一个友好提示
* 希望web层一定要处理,处理之后给用户一个友好提示,所以抛一个编译的异常
* 执行时异常是不行的,因为web层可处理可不处理
*/
throw new UserExistException();
} else {
//先对密码进行MD5加密
user.setPassword(ServiceUtils.md5(user.getPassword()));
dao.add(user);
}
}
@Override
public User login(String username,String password){
//先把密码md5一把再找
password = ServiceUtils.md5(password);
return dao.find(username,password);
}
}
这里用了工厂模式和MD5加密,先往下看,等等会解释。
五、web层开发
1.开发注册功能
创建一个RegisterUIServlet为用户提供注册用户界面,当RegisterUIServlet收到用户请求后,就跳转到register.jsp界面,在开发中如果项目中有一些敏感的web资源不想被外界直接访问,那么可以考虑将这些敏感的web资源放到WEB-INF目录下,这样就可以禁止外界直接通过URL来访问了。
RegisterUIServlet的代码如下:
package me.TiHom.web.UI;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 为用户提供注册用户界面的Servlet
* RegisterUIServlet负责为用户输出注册界面
* 当用户访问RegisterUIServlet时,就跳转到WEB-INF/pages目录下的register.jsp页面
*/
public class RegisterUIServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(req,resp);
}
}
register.jsp的代码如下:
<%--
Created by IntelliJ IDEA.
User: lenovo
Date: 2018/2/5
Time: 13:31
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
注册用户界面
欢迎来到注册用户界面!!!
这里就做一个简单的界面就好,你们如果有较好的前端基础可以进行改进,原谅博主对前端只懂个皮毛
疑问:
针对上面的
这里用了EL表达式,使用${pageContext.request.contextPath}等价于<%=request.getContextPath()%>,比如我的项目名是day01,那么在浏览器输出时是http://localhost:8080/day01/register.jsp
${pageContext.request.contextPath}取出来的就是/day01,而”/“代表的的就是http://localhost:8080。
2.在控制层中编写用于处理用户注册的Servlet
RegisterServlet的主要作用:
①接受客户端提交到服务器的表单数据
②校检表单数据的合法性,如果校检失败就返回register.jsp,并回显错误信息
③如果校检成功,调用service层向数据库中注册用户
为了方便Servlet中接收表单并且校检表单数据,我设计了一个用于校检注册表单数据的RegisterFormbean,再写WebUtils工具类,封装客户端提交的表单数据到formbean中。
RegisterFormbean的代码如下:
package me.TiHom.web.formbean;
import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
import java.util.HashMap;
import java.util.Map;
/**
* 封装的用户注册表单bean,用来接收register.jsp中的表单输入项的值
* RegisterFormBean中的属性与register.jsp中的表单输入项的name一一对应
* RegisterFormBean的职责除了负责接收register.jsp中的表单输入项的值之外还担任这校检表单输入值的合法性
*/
public class RegisterFormBean {
//这里的属性要与表单对应的name的值相同
private String username; //用户名
private String password; //密码
private String confirmPassword; //确认密码
private String email; //邮箱
private String birthday; //生日
private String nickname; //昵称
/**
* 存储校检时不通过时给用户的错误提示信息
*/
private Map errors = new HashMap();
public Map getErrors(){
return errors;
}
public void setErrors(Map errors){
this.errors = errors;
}
/**
* 负责校验输入项的合法性
* 用户名不能为空且要是3-16位字符的数字或字母
* 密码不能为空
* 两次密码要一致
* 邮箱可以为空,但是不为空时要合法
* 生日可以为空,但是不为空时要合法
* 昵称不能为空且要是3-16位的字符的数字或字母
* @return 表单是否合法
*/
public boolean validate() {
boolean isOk = true;
//对用户名合法性的校验
if (this.username == null || this.username.trim().equals("")) {
isOk = false;
errors.put("username", "用户名不能为空!!!");
} else {
if (!this.username.matches("[0-9a-zA-Z]{3,16}")) {
isOk = false;
errors.put("username", "用户名必须是3-16位的字母或数字!!!");
}
}
//对密码的合法性校验
if (this.password == null || this.password.trim().equals("")) {
isOk = false;
errors.put("password", "密码不能为空!!!");
}
//确认密码
if (!this.confirmPassword.equals(this.password)) {
isOk = false;
errors.put("confirmPassword", "两次密码不一致!!!");
}
//对邮箱的校验
if (this.email != null && !this.email.trim().equals("")) {
/*
* 邮箱在现实中存在的几种情况
* [email protected]
* [email protected]
* [email protected]
*/
if (!this.email.matches("\\w+@\\w+(\\.\\w+)+")) {
isOk = false;
errors.put("email", "邮箱不是一个合法的邮箱!!!");
}
}
//对生日日期的校检
if (this.birthday != null && this.birthday.trim().equals("")) {
try {
//这里是将字符串转换成日期,如果转换出错则会抛出异常进入catch区域
DateLocaleConverter conver = new DateLocaleConverter();
conver.convert(this.birthday,"yyyy-MM-dd HH:mm:ss");
} catch (Exception e) {
isOk = false;
errors.put("birthday", "生日必须要是一个日期!!!");
}
}
//对昵称的校检
if(this.nickname==null || this.nickname.trim().equals("")){
isOk = false;
errors.put("nickname","昵称不能为空!!!");
}else {
/*
* 昵称必须是中文
* 汉字区间:[\u4e00-\u9fa5]
*/
if(!this.nickname.matches("^([\\u4e00-\\u9fa5]+)$")){
isOk = false;
errors.put("nickname","昵称必须是汉字!!!");
}
}
return isOk;
}
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 getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
}
这里面涉及了正则表达式和对日期的校检:
1.解释下日期有关的问题:
编写一个测试类
会报异常
因此需要改进代码:只需改动x->8
正常运行
但是如果输入1980-10-32的话上述也不会出现异常,但是明显日期是非法的,所以继续往下
使用BeanUtils的日期转换器DateLocaleConverter
报异常
因此用这个方法来校检日期是最正确的!!!
2.关于正则表达式,我学的比较少,所以在以后深入学习后再补充~
3.创建WebUtils工具类
WebUtils工具类的的作用就是封装客户端提交的表单数据到formbean中
这里贴上WebUtils的代码:
package me.TiHom.web.utils; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.Converter; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.InvocationTargetException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Enumeration; import java.util.UUID; /** * 把request对象中的请求参数封装到bean中 */ public class WebUtils { /** * 将request对象转换成T对象 * @param request * @param clazz * @param
/** * 把request对象中的请求参数封装到bean中 */ public class WebUtils { /** * 将request对象转换成T对象 * @param request * @param clazz * @param* @return */ public staticT request2Bean(HttpServletRequest request,Class clazz){ try { //创建要封装数据的bean T bean = clazz.newInstance(); //把request中的数据整合到bean中 Enumeration e = request.getParameterNames(); while(e.hasMoreElements()){ String name = (String)e.nextElement(); String value = request.getParameter(name); BeanUtils.setProperty(bean,name,value); } return bean; } catch (Exception e) { throw new RuntimeException(e); } } public static void copyBean(Object src,Object dest){ //注册日期转换器 ConvertUtils.register(new Converter() { @Override public Object convert(Class type, Object value) { if(value==null){ return null; } String str = (String) value; if(str.trim().equals("")){ return null; } SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); try { return df.parse(str); } catch (ParseException e) { throw new RuntimeException(e); } } }, Date.class); try { /* * 在此项目中,是从formbean将属性拷贝到user对象中去,bean的拷贝 * 在实际开发中,是非常实用的 */ BeanUtils.copyProperties(dest,src); } catch (Exception e) { throw new RuntimeException(e); } } /** * 产生全球唯一的id * @return */ public static String makeId(){ //UUID算法根据你系统的网卡的xx地址、CPU、机器的型号等等生成一个128位长的字符串 return UUID.randomUUID().toString(); } } * @return */ public staticT request2Bean(HttpServletRequest request,Class clazz){ try { //创建要封装数据的bean T bean = clazz.newInstance(); //把request中的数据整合到bean中 Enumeration e = request.getParameterNames(); while(e.hasMoreElements()){ String name = (String)e.nextElement(); String value = request.getParameter(name); BeanUtils.setProperty(bean,name,value); } return bean; } catch (Exception e) { throw new RuntimeException(e); } } public static void copyBean(Object src,Object dest){ //注册日期转换器 ConvertUtils.register(new Converter() { @Override public Object convert(Class type, Object value) { if(value==null){ return null; } String str = (String) value; if(str.trim().equals("")){ return null; } SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); try { return df.parse(str); } catch (ParseException e) { throw new RuntimeException(e); } } }, Date.class); try { /* * 在此项目中,是从formbean将属性拷贝到user对象中去,bean的拷贝 * 在实际开发中,是非常实用的 */ BeanUtils.copyProperties(dest,src); } catch (Exception e) { throw new RuntimeException(e); } } /** * 产生全球唯一的id * @return */ public static String makeId(){ //UUID算法根据你系统的网卡的xx地址、CPU、机器的型号等等生成一个128位长的字符串 return UUID.randomUUID().toString(); } }
再来看看RegisterServlet的代码:
package me.TiHom.controller;
import me.TiHom.domain.User;
import me.TiHom.exception.UserExistException;
import me.TiHom.web.formbean.RegisterFormBean;
import me.TiHom.web.service.UserService;
import me.TiHom.web.service.impl.BusinessServiceImpl;
import me.TiHom.web.utils.WebUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
/**
* 处理用户注册的Servlet
*/
public class RegisterServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//将客户端提交的表单数据封装到RegisterFormBean对象中
RegisterFormBean formBean = WebUtils.request2Bean(req,RegisterFormBean.class);
//校检用户注册填写的表单数据
if(!formBean.validate()){
//将封装了用户填写的表单数据的formBean对象发送回register.jsp页面的form表单中进行显示
req.setAttribute("formBean",formBean);
//校检失败就说明是用户填写的表单数据有问题,那么就跳转回register.jsp
req.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(req,resp);
return;
}
User user = new User();
try {
//WebUtils.copyBean(formBean,user);
//注册字符串到日期的转换器
ConvertUtils.register(new DateLocaleConverter(), Date.class);
//把表单数据填充到JavaBean中
BeanUtils.copyProperties(user,formBean);
//设置用户的ID属性
user.setId(WebUtils.makeId());
UserService service = new BusinessServiceImpl();
//调用service层提供的注册用户服务实现用户注册
service.register(user);
String message = String.format(
"注册成功!!3秒后为您自动跳转到登录界面!!",
req.getContextPath()+"/servlet/LoginUIServlet");
req.setAttribute("message",message);
req.getRequestDispatcher("/message.jsp").forward(req,resp);
} catch (UserExistException e){
formBean.getErrors().put("username","注册用户已经存在!!!");
req.setAttribute("formBean",formBean);
req.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(req,resp);
} catch (Exception e) {
e.printStackTrace(); //在后台记录异常
req.setAttribute("message","对不起,注册失败!!!");
req.getRequestDispatcher("/message.jsp").forward(req,resp);
}
}
}
/**
* 处理用户注册的Servlet
*/
public class RegisterServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//将客户端提交的表单数据封装到RegisterFormBean对象中
RegisterFormBean formBean = WebUtils.request2Bean(req,RegisterFormBean.class);
//校检用户注册填写的表单数据
if(!formBean.validate()){
//将封装了用户填写的表单数据的formBean对象发送回register.jsp页面的form表单中进行显示
req.setAttribute("formBean",formBean);
//校检失败就说明是用户填写的表单数据有问题,那么就跳转回register.jsp
req.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(req,resp);
return;
}
User user = new User();
try {
//WebUtils.copyBean(formBean,user);
//注册字符串到日期的转换器
ConvertUtils.register(new DateLocaleConverter(), Date.class);
//把表单数据填充到JavaBean中
BeanUtils.copyProperties(user,formBean);
//设置用户的ID属性
user.setId(WebUtils.makeId());
UserService service = new BusinessServiceImpl();
//调用service层提供的注册用户服务实现用户注册
service.register(user);
String message = String.format(
"注册成功!!3秒后为您自动跳转到登录界面!!",
req.getContextPath()+"/servlet/LoginUIServlet");
req.setAttribute("message",message);
req.getRequestDispatcher("/message.jsp").forward(req,resp);
} catch (UserExistException e){
formBean.getErrors().put("username","注册用户已经存在!!!");
req.setAttribute("formBean",formBean);
req.getRequestDispatcher("/WEB-INF/pages/register.jsp").forward(req,resp);
} catch (Exception e) {
e.printStackTrace(); //在后台记录异常
req.setAttribute("message","对不起,注册失败!!!");
req.getRequestDispatcher("/message.jsp").forward(req,resp);
}
}
}
用户注册时如果填写的表单数据校验不通过,那么服务器端就将一个存储了错误提示消息和表单数据的formbean对象存储到request对象中,然后发送回register.jsp页面,因此我们需要在register.jsp页面中取出request对象中formbean对象,然后将用户填写的表单数据重新回显到对应的表单项上面,将出错时的提示消息也显示到form表单上面,让用户知道是哪些数据填写不合法! (其实这里可以使用Ajax技术,有时间补上)
修改register.jsp页面,代码如下:
<%--
Created by IntelliJ IDEA.
User: lenovo
Date: 2018/2/5
Time: 13:31
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
注册用户界面
欢迎来到注册用户界面!!!
到这里基本注册功能就已经完善好了。
4.开发登录功能
直接贴代码不多说:
login.jsp
<%--
Created by IntelliJ IDEA.
User: lenovo
Date: 2018/2/6
Time: 11:21
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
用户登录
LoginUIServlet的代码:
package me.TiHom.web.UI;
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 LoginUIServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
LoginServlet的代码:
package me.TiHom.controller;
import me.TiHom.domain.User;
import me.TiHom.web.service.UserService;
import me.TiHom.web.service.impl.BusinessServiceImpl;
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 {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取用户输入的用户名
String username = req.getParameter("username");
//获取用户输入的密码
String password = req.getParameter("password");
UserService service = new BusinessServiceImpl();
//用户登录
User user = service.login(username,password);
if(user==null){
String message = String.format(
"对不起,用户名或密码有错误!请重新登录!2秒后为您自动跳转到登录界面!!
这样登录功能就开发好了。
5.开发注销功能
这里直接贴代码:
LogoutServlet的代码如下:
package me.TiHom.controller;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LogoutServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
if(session!=null){
session.removeAttribute("user");
}
//注销成功
req.setAttribute("message", "注销成功,浏览器将在3秒后跳转,如果没有跳转,你就点...!!");
req.getRequestDispatcher("/message.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
message.jsp的代码:
<%--
Created by IntelliJ IDEA.
User: lenovo
Date: 2018/2/6
Time: 12:05
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
全局消息显示界面
${message}
LoginUIServlet
me.TiHom.web.UI.LoginUIServlet
RegisterUIServlet
me.TiHom.web.UI.RegisterUIServlet
RegisterServlet
me.TiHom.controller.RegisterServlet
LoginServlet
me.TiHom.controller.LoginServlet
LogoutServlet
me.TiHom.controller.LogoutServlet
LoginUIServlet
/servlet/LoginUIServlet
RegisterUIServlet
/servlet/RegisterUIServlet
RegisterServlet
/servlet/RegisterServlet
LoginServlet
/servlet/LoginServlet
LogoutServlet
/servlet/LogoutServlet
EncodingFilter
me.TiHom.web.filter.CharacterEncodingFilter
encoding
UTF-8
EncodingFilter
/*
index.jsp
这里过滤器的作用是设置全局编码格式,代码如下:
package me.TiHom.web.filter;
import javax.servlet.*;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
//存储系统使用的字符编码
private String encoding = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.encoding = filterConfig.getInitParameter("encoding");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding(encoding);
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
index.jsp的代码也贴上:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
Created by IntelliJ IDEA.
User: lenovo
Date: 2018/2/4
Time: 10:43
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
首页
TiHom的网站
注册
登陆
欢迎您:${user.username}
经过我的测试没有任何错误,大家可以放心使用,随后我也会把源码放在GitHub上供大家下载。
1.搭建开发环境:博主使用的是较为普遍的IDEA、Tomcat服务器、Mysql数据库。
先把lib导入,然后将各个层进行分包,并不是说这些都是必备的,但是这样分包的好处是在以后的维护和管理上清晰明了,而不会造成多重逻辑的混乱。
缺点是在小项目这样分包会导致包过多而显得过于复杂。
部署tomcat服务器
2.开发数据库连接类
我本人倾向于先开发数据库连接类,然后在类中定义main方法先进行测试,成功才进行下一步编辑。(仅属于个人习惯)。推荐有能力的多学习用数据库连接池技术,目前很多使用阿里的druid连接池技术,通用的有c3p0和dbcp连接池技术。(如果有时间我会总结一下,博主是大一的新手,如果谁有好的总结可以在评论推荐一下)
3.开发domain
这里面主要是一些实体类,如User类。
4.开发dao层
①dao操作接口:每一个dao操作接口规定了一张表在一个项目中的具体操作方法,此接口的名称最好按照如下的格式编写:”表名称Dao“
dao接口方法如下名编写:
②dao层接口的实现类:开发与数据库进行数据交互的类,因为层层递进,所以业务逻辑处理应该从dao层开始开发。一般包含数据库的CURD操作。
流程:注册就对应的先将用户输入的数据接收后转为User对象,然后在dao层的doAdd方法中添加用户进入数据库中(这里可以在juint中创建一个专门检验是否能够正常操作数据库的测试类)
查询findUser(String username,String password)方法和findUser(String username)方法,前者在登录时需要在数据库中检查是否有这个用户,后者是在注册时查询是否造成用户用户名重复。
5.开发service层
先写到这里明天介绍工厂模式...
大家可以看我下一篇文章关于工厂模式和单例模式的。