javaEE之MVC三层架构及注册登入案例

时间:2021-05-22 20:57:02

一、MVC之三层架构

1、Servlet和JSP(模型1:JSP+javabean)

最佳实践:Servlet处理逻辑,把结果封装到域对象中(ServletRequest、HttpSession、ServletContext),转发给JSP,让JSP只负责显示。

数据的封装要用到JavaBean。架构思路如下:

javaEE之MVC三层架构及注册登入案例

2、MVC和三层架构图(模型2)

降低了各层之间的依赖,方便后期扩展与维护

javaEE之MVC三层架构及注册登入案例

3、开发顺序:

(1)javabean开始 com.fengyuwuzu.domain

封装数据,名词:用户

(2)业务接口com.fengyuwuzu.service

BusinessService:

void regist(User user) throws UserExistException;

User login(String username,String password);

(3)DAO接口com.fengyuwuzu.dao

void save(User user);

User findUser(String username);

User findUser(String username,String password);

(4)DAO实现com.fengyuwuzu.dao.impl

public class UserDaoMySQLImpl implements UserDao

(5)业务实现com.fengyuwuzu.service.impl

public class BusinessServiceImpl implements BusinessService

(6)单元测试com.fengyuwuzu.test

(7)表现层:com.fengyuwuzu.web.controller

html+jsp+servlet。LoginServlet+LogoutServlet+RegistServlet

(8)工具类com.fengyuwuzu.util

JdbcUtil、FillBeanUtil

二、登入注册案例

1、创建javabean及数据库表:

首先我们根据目的,来创建javabean,我们希望实现登入和注册,那么现在我们针对是用户注册信息。

public class User implements Serializable {
private String username;
private String password;
private String email;
private Date birthday;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}。。。

use day15;
create table user(
username varchar(100) primary key,
password varchar(100) not null,
email varchar(100) not null,
birthday date
);

2、业务接口

有了javabean我们操作的对象也就明确了,这个时候我们要明确我们要做什么,现在我们要注册和登入,所以在业务逻辑层,我们要实现的是注册和登入函数。这里只是根据要设计的功能,写出接口函数。

//根据需求来定
//接口:把注释写的没有歧义
public interface BusinessService {
/**
* 用户注册
* @param user 注册信息
* @throws UserExistException 如果注册用户名已经存在了,抛出此异常
*/
void regist(User user) throws UserExistException;
/**
* 完成用户登录
* @param username 用户名
* @param password 密码
* @return 如果用户名或密码错误,要返回null
*/
User login(String username,String password);
}

3、DAO接口

我们明确了业务要实现的几个功能,而这些功能依赖于持久层的数据,我们要明确持久层的操作,即数据的保存和查找:

//不负责业务逻辑,只负责CRUD
public interface UserDao {
/**
* 保存用户信息
* @param user
*/
void save(User user);
/**
* 根据用户名查询用户
* @param username
* @return 如果不存在返回null
*/
User findUser(String username);
/**
* 根据用户名和密码查询用户
* @param username
* @param password
* @return 如果不存在返回null
*/
User findUser(String username,String password);
}

4、DAO实现

明确了底层要进行数据的保存和查找,那么现在我们可以实现DAO层的具体实现,这样我就可以接着实现业务逻辑层的实现了。

DAO的实现就是:连接数据库,进行数据库的CRUD

public class UserDaoMySQLImpl implements UserDao {

public void save(User user) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = JdbcUtil.getConnection();
stmt = conn.createStatement();
stmt.executeUpdate("insert into user (username,password,email,birthday) values ('"+user.getUsername()+"','"+user.getPassword()+"','"+user.getEmail()+"','"+user.getBirthday().toLocaleString()+"')");
}catch(Exception e){
throw new DaoException(e);
}finally{
JdbcUtil.release(rs, stmt, conn);
}
}

public User findUser(String username) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = JdbcUtil.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from user where username='"+username+"'");
if(rs.next()){
User user = new User();
user.setUsername(rs.getString("username"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
return user;
}else{
return null;
}
}catch(Exception e){
throw new DaoException(e);
}finally{
JdbcUtil.release(rs, stmt, conn);
}
}

public User findUser(String username, String password) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = JdbcUtil.getConnection();
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from user where username='"+username+"' and password='"+password+"'");
if(rs.next()){
User user = new User();
user.setUsername(rs.getString("username"));
user.setEmail(rs.getString("email"));
user.setBirthday(rs.getDate("birthday"));
return user;
}else{
return null;
}
}catch(Exception e){
throw new DaoException(e);
}finally{
JdbcUtil.release(rs, stmt, conn);
}
}

}

5、业务实现

我们实现了DAO接口,并具体实现了DAO操作的实现,那我们业务逻辑的实现就可以利用DAO的实现来操作数据库的内容了。

业务实现,是为servlet服务的,这样servlet就可以调用这里实现的方法操作到底层的数据了。

public class BusinessServiceImpl implements BusinessService {
private UserDao dao = BeanFactory.getUserDao();
public void regist(User user) throws UserExistException {
if(user==null)
throw new IllegalArgumentException("The param user can not be null");
User dbUser = dao.findUser(user.getUsername());
if(dbUser!=null){
throw new UserExistException("The username \""+user.getUsername()+"\"用户已经存在");
}
dao.save(user);
}

public User login(String username, String password) {
return dao.findUser(username, password);
}

}

6、单元测试

之上我们实现了业务逻辑和DAO层的东西,那么现在我们可以进行单元测试,测试业务逻辑层对数据库的操作是否都是正常的,一旦测试通过,证明我们业务逻辑都已经完全打通,可以交给表现层调用了

7、表现层

用户点击-->触发 servlet被调用-->servlet里面创建业务逻辑的实例,来调用里面的方法-->持久层数据被操作。

(1)首页jsp:

  <body>
<h1>XX网站</h1>
<hr/>
<c:if test="${sessionScope.user==null}">
<a href="${pageContext.request.contextPath}/regist.jsp">注册</a>
<a href="${pageContext.request.contextPath}/login.jsp">登录</a>
</c:if>
<c:if test="${sessionScope.user!=null}">
欢迎您:${sessionScope.user.username}
<a href="${pageContext.request.contextPath}/servlet/LogoutServlet">注销</a>
</c:if>
</body>

(2)注册jsp

  <body>
<form action="${pageContext.request.contextPath}/servlet/RegistServlet" method="post" enctype="application/x-www-form-urlencoded">
<!--
约定优于编码:遵守好的约定,会使代码编写更加高效
目前约定:表单的字段名和JavaBean的属性名保持了一致
-->
<table border="1" width="738">
<tr>
<td>用户名:</td>
<td>
<input type="text" name="username" value="${formBean.username}"/>${formBean.errors.username}
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input type="password" name="password" value=""/>${formBean.errors.password}
</td>
</tr>
<tr>
<td>确认密码:</td>
<td>
<input type="password" name="repassword"/>${formBean.errors.repassword}
</td>
</tr>
<tr>
<td>邮箱:</td>
<td>
<input type="text" name="email" value="${formBean.email}"/>${formBean.errors.email}
</td>
</tr>
<tr>
<td>生日yyyy-MM-dd:</td>
<td>
<input type="text" name="birthday" value="${formBean.birthday}" readonly="readonly" onClick="return showCalendar('birthday', 'yy-mm-dd');"/>${formBean.errors.birthday}
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="注册"/>
</td>
</tr>
</table>
</form>
</body>
(3)登入jsp

 <body>
<form action="${pageContext.request.contextPath}/servlet/LoginServlet" method="post" enctype="application/x-www-form-urlencoded">
<table border="1" width="438">
<tr>
<th>用户名:</th>
<td>
<input type="text" name="username"/>
</td>
</tr>
<tr>
<th>密码:</th>
<td>
<input type="text" name="password"/>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="登录"/>
</td>
</tr>
</table>
</form>
</body>
(4)RegistServlet
//编码重点。完成注册
public class RegistServlet extends HttpServlet {
private BusinessService s = new BusinessServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String encoding = "UTF-8";
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);

//获取表单数据,封装到JavaBean中。引入FormBean:特点属性和表单字段完全一致。且都是String类型。封装错误消息。
UserFormBean formBean = FillBeanUtil.fillBean(request, UserFormBean.class);
//数据验证:服务器端验证。实际开发中:客户端+服务器端验证。
if(!formBean.validate()){
//不通过:回显数据,消息提示
request.setAttribute("formBean", formBean);
request.getRequestDispatcher("/regist.jsp").forward(request, response);
return;
}

//填充模型:formBean---->JavaBean
User user = new User();
//user.setUsername(formBean.getUsername());
//user.setPassword(formBean.getPassword());
//user.setEmail(formBean.getEmail());
//DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
//try {
//user.setBirthday(df.parse(formBean.getBirthday()));
//} catch (ParseException e) {
//e.printStackTrace();
//}

ConvertUtils.register(new DateLocaleConverter(), Date.class);//注册类型转换器
try {
BeanUtils.copyProperties(user, formBean);
} catch (Exception e) {
e.printStackTrace();
}
//通过:调用Service保存数据
try {
s.regist(user);
response.getWriter().write("保存成功!2秒后转向主页");
response.setHeader("Refresh", "2;URL="+request.getContextPath());
} catch (UserExistException e) {
//数据回显和提示
formBean.getErrors().put("username", "用户名已经存在了");
request.setAttribute("formBean", formBean);
request.getRequestDispatcher("/regist.jsp").forward(request, response);
return;
}
}
(5)LoginServlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String encoding = "UTF-8";
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);

String username = request.getParameter("username");
String password = request.getParameter("password");

User user = s.login(username, password);
if(user==null){
//错误的用户名或密码
response.getWriter().write("错误的用户名或密码。2秒后转向登录页面。");
response.setHeader("Refresh", "2;URL="+request.getContextPath()+"/login.jsp");
return;
}

//登录成功
request.getSession().setAttribute("user", user);
response.getWriter().write("登录成功。2秒后转向主页。");
response.setHeader("Refresh", "2;URL="+request.getContextPath());

}
(6)LogoutServlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String encoding = "UTF-8";
request.setCharacterEncoding(encoding);
response.setContentType("text/html;charset="+encoding);

request.getSession().removeAttribute("user");
//request.getSession().invalidate();
response.getWriter().write("注销成功。2秒后转向主页。");
response.setHeader("Refresh", "2;URL="+request.getContextPath());
}
8、工具类

为了简化代码,避免重复性的代码,将常用的代码抽取出来。如数据库操作,javabean填充等

(1)JdbcUtil

//与具体的数据库解耦
public class JdbcUtil {

private static String driverClass;
private static String url;
private static String user;
private static String password;

static{
try {
InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("dbcfg.properties");
Properties props = new Properties();
props.load(in);

driverClass = props.getProperty("driverClass");
url = props.getProperty("url");
user = props.getProperty("user");
password = props.getProperty("password");
Class.forName(driverClass);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}

}

public static Connection getConnection() throws Exception {
Connection conn = DriverManager.getConnection(url,user,password);
return conn;
}

public static void release(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}

(2)填充javabean

依赖于:

commons-beanutils-1.8.3.jar

commons-logging-1.1.1.jar

public class FillBeanUtil {
public static <T> T fillBean(HttpServletRequest request,Class<T> clazz){
try {
T bean = clazz.newInstance();
BeanUtils.populate(bean, request.getParameterMap());
return bean;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

(3)BeanFactory

public class BeanFactory {

private static String userDao;
static{
try {
InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("dao.properties");
Properties props = new Properties();
props.load(in);
userDao = props.getProperty("userDao");
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}

public static UserDao getUserDao(){
try {
return (UserDao) Class.forName(userDao).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}


myeclipse工程代码下载:

http://download.csdn.net/detail/fengyuwuzu0519/9899979