第一次试着以规范的MVVC设计模式写了OA部分的功能。写完以后,对MVC这种著名的设计模式有了一些具体的理解和心得体会。
MVC百度百科如是说:
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
将模型(model)-视图(view)-控制器(controller)三层分离,实现层与层之间尽可能低的耦合性,利于框架的维护与扩展。牺牲了性能,换取了系统弹性。所谓系统弹性,就是怎么搞也搞不跨的性能。
在经典的J2EE中:
1.jsp在View层接收用户的操作,如提交表单等。收到请求后,调用controller层的servelt来处理这个request。
2.servelt调用业务逻辑层service中的方法来处理这个请求。
3.javabean则为封装了数据实体的对象,每实例化一个javabean,则可理解为创建了一个和数据库中表里一张数据对应的一个对象。在dao层中通过连接数据库,实现具体的数据访问操作,如连接、增、删、改、查等等。
4.在看过了网上的一些源码和别人写的一些DEMO后,在分包的时候,javabean所在的包名可以叫做 domain(域模型),entity(实体),bean。在过去搞安卓应用开发的时候,我多用entity,在J2EE中,现在看来,更适合于管理数据实体javabean的domain层。
关于MVC模式的项目中分包名的概述。
M:代表model,可以理解为javaBean;
V:代表view,可以理解为jsp;
c:代表controller,可以理解为action;
1.domain:这一层是用来管理javaBean实体对象的;
2.dao:数据访问层,对数据库进行访问;
3.service:业务逻辑层,通过调用dao层来对数据库进行访问;
4.web:数据显示层;
接下来,以最近写的OA系统为例,逐步分析这个最简单的DEMO中体现的MVC设计。
——————————————————————————————————————————————————————————————————————————
首先是工程包结构:
整个工程分为5块
1.controller:控制层,包含servelt,负责接收用户响应以及回复给用户结果视图。
2.dao:数据访问层。在dao层中首先定义了接口(UsersDao),并在其中分出impl包,实现dao中的接口,连接数据库,并实现基本的数据操作。在本OA系统中,即为用户是否可以成功登陆。
3.service业务逻辑层。在OA系统中,业务逻辑较为简单,就是登录。但在一些大型的如电商或是企业管理系统中,业务逻辑可能会比较复杂,如积分会员,获取详情等等。
4.domain域模型层,此层中包含对javabean实体对象的管理,在OA系统中,需要的实体对象只有一个(Users,请无视那个无关的Books)
5.util公用方法层,在OA系统中,我只写了连接数据库的相关操作。获取连接对象,增删改查,执行SQL语句等。还可以补充一个获取系统时间的util。
其他:那个Test层是开发调试过程中,用来测试数据库连接是否正常,增删改查是否成功执行等。
接下来看各层的类定义与实现。
首先是dao层。
UsersDao是一个接口,定义了数据访问中需要实现的方法。
package com.kyy.dao;
import com.kyy.domain.Users;
public interface UsersDao {
public Boolean isLogin(Users user);
}
UsersDaoImpl是这个接口的实现。
package com.kyy.dao.impl;
import java.sql.SQLException;
import com.kyy.dao.UsersDao;
import com.kyy.domain.Users;
import com.kyy.util.DBHelp;
public class UsersDaoImpl implements UsersDao {
@Override
public Boolean isLogin(Users user) {
// TODO Auto-generated method stub
boolean ret=false;
String sql="select * from users where name='%s' and pwd='%s'";
try {
if(DBHelp.dbQuery(String.format(sql, user.getName(),user.getPwd())).next()) {
ret=true;
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ret;
}
}
接着是业务逻辑service层。因为本OA系统中数据访问中的方法 是否能成功登陆与业务逻辑层中的是否能登陆一样,在业务逻辑层的接口实现中,只需要实例化一个Dao对象,并调用Dao层中方法即可。
UsersService.java
package com.kyy.service;
import com.kyy.domain.Users;
public interface UserService {
public boolean isLogin(Users User);
}
UsersServiceImpl.java
package com.kyy.service.impl;
import com.kyy.dao.UsersDao;
import com.kyy.dao.impl.UsersDaoImpl;
import com.kyy.domain.Users;
import com.kyy.service.UserService;
public class UsersServiceImpl implements UserService{
UsersDao dao=new UsersDaoImpl();
@Override
public boolean isLogin(Users User) {
// TODO Auto-generated method stub
return dao.isLogin(User);
}
}
最后是控制层controller
通过servelt接受用户的action,并转交给业务逻辑service层来处理
UsersAction.java
package com.kyy.controller;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.kyy.domain.Users;
import com.kyy.service.UserService;
import com.kyy.service.impl.UsersServiceImpl;
/**
* Servlet implementation class MainMall
*/
public class UsersAction extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UsersAction() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//response.getWriter().append("Served at: ").append(request.getContextPath());
//this.doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
//doGet(request, response);
String name=request.getParameter("name");
String pwd=request.getParameter("pwd");
Users loginuser=new Users();
loginuser.setName(name);
loginuser.setPwd(pwd);
UserService service=new UsersServiceImpl();
PrintWriter out=response.getWriter();
if(service.isLogin(loginuser)) {
//getServletContext().getRequestDispatcher("mainmall.jsp").forward(request, response);
out.println("YES!");
}else {
//getServletContext().getRequestDispatcher("index.jsp").forward(request, response);
out.println("NO!");
}
}
}
在实现一个servelt后,记得在web.xml中实现对servlet的注册配置以及路由映射。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>bookshop</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>UsersAction</servlet-name>
<servlet-class>com.kyy.controller.UsersAction</servlet-class>
</servlet>
<!-- ... -->
<servlet-mapping>
<servlet-name>UsersAction</servlet-name>
<url-pattern>/UsersAction.do</url-pattern>
</servlet-mapping>
</web-app>
在util包中封装关于数据库的连接以及操作。
DBHelp.java
package com.kyy.util;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Statement;
public class DBHelp {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL="jdbc:mysql://xx.xx.xx.xxx:xxxx/xxxxxxxxx";
private static final String PASSWORD="xxxxxxxxxx";
private static final String USER="xxxx";
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName(DRIVER); // 加载数据库驱动
if (null == conn) {
conn = (Connection) DriverManager.getConnection(URL, USER, PASSWORD);
}
} catch (ClassNotFoundException e) {
System.out.println("Sorry,can't find the Driver!");
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
public static int executeNonQuery(String sql) {
int result = 0;
Connection conn = null;
Statement stmt = null;
try {
conn = getConnection();
stmt = (Statement) conn.createStatement();
result = stmt.executeUpdate(sql);
} catch (SQLException err) {
err.printStackTrace();
free(null, stmt, conn);
} finally {
free(null, stmt, conn);
}
return result;
}
public static ResultSet dbQuery(String sql) {
Connection conn = null;
Statement stmt = null;
ResultSet rs=null;
try {
conn = getConnection();
stmt = (Statement) conn.createStatement();
rs = stmt.executeQuery(sql);
} catch (SQLException sqlex) {
System.out.println("数据库查询异常:");
sqlex.printStackTrace();
free(null,stmt,conn);
}
return rs;
}
public static int dbUpdate(String sql) {
Connection conn = null;
Statement stmt = null;
int rs=0;
try {
conn = getConnection();
stmt = (Statement) conn.createStatement();
//System.out.println("更新语句..."+sql);
rs = stmt.executeUpdate(sql);
} catch (SQLException sqlex) {
System.out.println("数据库更新异常:");
sqlex.printStackTrace();
free(null,stmt,conn);
}finally {
free(null,stmt,conn);
}
return rs;
}
public static void free(ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
} catch (SQLException err) {
err.printStackTrace();
}
}
public static void free(Statement st) {
try {
if (st != null) {
st.close();
}
} catch (SQLException err) {
err.printStackTrace();
}
}
public static void free(Connection conn) {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException err) {
err.printStackTrace();
}
}
public static void free(ResultSet rs, Statement stmt, Connection conn) {
free(rs);
free(stmt);
free(conn);
}
}
最后是负责用户界面view的jsp视图
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>bookshop</title>
</head>
<body>
<form action="UsersAction.do" method="post">
<p>用户名: <input type="text" name="name" /></p>
<p>密码: <input type="text" name="pwd" /></p>
<input type="submit" value="Submit" />
</form>
</body>
</html>
数据库中的表信息如下
运行结果如下
当输入正确的用户名和密码时
结果如下
当输入错误的用户名和密码时
结果
最后用C#写的HTTP测试工具测试一下
可以看到 Body里的Yes
此外,我并没有重写servelt里的doget方法,所以,直接通过访问网页,执行get请求时无任何返回。
至此,整个OA模块的功能都被打通了。以此文为记,作为从Android移动端转向J2EE WEB开发的新起点。
(要是明年能给宝宝个开发岗的实习就好了~~~~~~)