MVC让简单的业务也变得复杂
不知道你在使用MVC模式开发项目的时候是否觉得很麻烦,一个简单的增删改查动作却要涉及到多个文件操作。
以一条数据增加为例说明。
假设我们使用hibernate并且dao层是已经封装好的
从图中可以看出如果我们在系统中写一个增加功能需要自己动手写的地方至少是 jsp , action , service,servicesImpl 四层。
如果是复杂的添加操作那么我们很可能还会自己定义dao层的接口和方法,那样就是6层操作了。
如果使用mybatis 至少也是写4层,常见的情况也是写6层,因为我们需要自己写一些sql语句,
这样就要写mapper.xml 和mapper.java 因此因为是6层。
一个简单的动作写4层或者6层我总觉得是那么麻烦的一件事情,而且容易出错。
如果有一天这个新增动作需要添加一个字段,那么放在谁的目前都是一个蛋疼的动作了,添加一个字段足以让你恶心半天了。
我们来看看要修改多少地方
1、数据库
2、pojo
3、dao的配置文件
4、界面
可能还要修改action等其他地方。而且配置文件一动很容易出现bug。。。
哎总之我受够了这样的日子咯。。。。。
两层精简架构
后来进入湖南比联科技后再公司框架的启发下我改造了一个使用springMvc 和 oracle存储过程实现web架构的2层结构,从此福音到了
先看一个简化的流程图吧
我们把所有的业务逻辑通过oracle的过程来实现,然后只需要在页面调用我们写好的JavaScript库就可以直接拿到过程处理的结果。
所以大部分的业务我们都只要2处理2个地方就可以了,先写过程在写界面调用。是不是很方便呢?而且过程处理的数据比mvc可是快很多哦,
至于界面显示方面也是,html界面的读取速度远远大于jsp页面,所以性能方面是一个极大的提高。
还有我们这里没有了pojo 所以如果修改字段,也不需要改动任何东西,改一下存储过程和页面就好了工作量比MVC中少了一倍。也就是说工作效率提高了2倍哦。
原理就是图上所表示的下面用代码来说明一下(以一个功能管理为例子):
数据库表
-- Create table
create table EX_SYS_POWER
(
ID INTEGER not null,
ICON_PATH VARCHAR2(500),
FUNCTION_PATH VARCHAR2(1000),
MARK VARCHAR2(4000),
STATE INTEGER,
GRADE INTEGER,
PARENT_ID INTEGER,
YXBZ INTEGER,
NAME VARCHAR2(500)
)
存储过程
CREATE OR REPLACE PACKAGE BODY A_ES_POWER IS
--=============根据id查询
PROCEDURE FIND_POWER_BYID(P_ID INTEGER,
P_RESULT OUT PLAT_CONSTANT.RESULTSET) IS
BEGIN
OPEN P_RESULT FOR
SELECT *
FROM EX_SYS_POWER
WHERE ID = P_ID
AND YXBZ = 1;
END;
END;
html界面
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="../../public/hui/lib/jquery/1.9.1/jquery.min.js" ></script>
<script type="text/javascript" src="../../public/exctscript/AjaxProxy.js" ></script>
<title>空白页</title>
</head>
<body>
<a onclick="test()" href="javascript:void(0);" class='btn btn-success' >测试查询</a>
<a onclick="test2()" href="javascript:void(0);" >字段测试</a>
<script type="text/javascript">
function test(){
var loj=new AjaxProxy();
loj.addParm(1, "1");
loj.invoke("SCOTT.A_ES_POWER.FIND_POWER_BYID", function(result){
alert(loj.getString("P_RESULT",1,"ICON_PATH"));
alert(loj.getRowCount("P_RESULT")); });
}
</script>
</body>
</html>
Ajaxprox.js
/**
* author :姜友瑶
*/
function getRootPath() {
var curWwwPath = window.document.location.href;
var pathName = window.document.location.pathname;
return curWwwPath.substring(0, curWwwPath.indexOf(pathName))
+ pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
}
var basePath = getRootPath();
document.write('<script type="text/javascript" src="' + basePath
+ '/public/hui/lib/layer/1.9.3/layer.js" ></script>');
function AjaxProxy(async) {
if (async != null) {
this.async = async;
} else {
this.async = true;
}
this.gs_parameter = {};
this.STATE_SUCCESS = '1';
this.STATE_ERR = '0';
this.result = null;
}
AjaxProxy.prototype.invoke = function(procedure, callback) {
var url = basePath + "/center.do?p_id=" + procedure;
var $this = this;
layer.msg('加载中', {
icon : 16
});
if (this.async) {//异步
$.ajax({
type : "post",
url : url,
data : this.gs_parameter,
async : true,
success : function(callbackData) {
var result = eval(callbackData);
if (result.requestStatus == 0) {
layer.closeAll('dialog');
layer.msg(result.errMsg, {
icon : 2
});
return;
} else {
$this.result = result;
layer.closeAll('dialog');
callback();
}
}
});
} else { // 同步
$.ajax({
type : "post",
url : url,
data : this.gs_parameter,
async : false,
success : function(callbackData) {
var result = eval(callbackData);
if (result.requestStatus == 0) {
layer.closeAll('dialog');
layer.msg(result.errMsg, {
icon : 2
});
return;
} else {
$this.result = result;
layer.closeAll('dialog');
callback();
}
}
});
}
};
AjaxProxy.prototype.addParm = function(index, value) {
if (value != null) {
value += "";
value = encodeURIComponent(value);
this.gs_parameter["param_" + index] = value;
}
};
AjaxProxy.prototype.getRowCount = function(mapName) {
return eval("this.result." + mapName + "['row_count']");
};
AjaxProxy.prototype.getValue = function(key) {
return eval("this.result." + key);
};
AjaxProxy.prototype.getString = function(mapName, index, key) {
return eval("this.result." + mapName + ".row_value[" + index + "]['" + key
+ "']");
};
Java调用Oracle存储过程
步骤:
1、编写Oracle存储过程
2、编写数据库获取连接工具类
3、编写简单应用调用存储过程
实现:
1、Oracle存储过程:
/*测试表*/
create table test(
id varchar2(32),
name varchar2(32)
);
/*存储过程 插入数据*/
CREATE OR REPLACE PROCEDURE insert_procedure(
PARA1 IN VARCHAR2,
PARA2 IN VARCHAR2
) AS
BEGIN
INSERT INTO test (id, name) VALUES (PARA1, PARA2);
END insert_procedure;
/*存储过程 返回结果集*/
CREATE OR REPLACE PROCEDURE select_procedure(
para_id IN VARCHAR2,
name OUT sys_refcursor /* 这个sys_refcursor类型在SYS.STANDARD包中 */
) AS
BEGIN
OPEN name FOR
SELECT * FROM test WHERE id = para_id;
END;
2、JDBC工具类
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DBUtil {
public static final String DRIVER = "oracle.jdbc.driver.OracleDriver";
public static final String URL = "jdbc:oracle:thin:@localhost:1521/orcl";
public static final String USERNAME = "pfm";
public static final String PASSWORD = "pfm";
/**
* 通过静态代码块 注册数据库驱动
*/
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获得Connection
*
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 获得Statement
*
* @return
*/
public static Statement getStatement() {
Statement st = null;
try {
st = getConnection().createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
return st;
}
/**
* 关闭ResultSet
*
* @param rs
*/
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭Statement
*
* @param st
*/
public static void closeStatement(Statement st) {
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭Connection
*
* @param conn
*/
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭全部
*
* @param rs
* @param sta
* @param conn
*/
public static void closeAll(ResultSet rs, Statement sta, Connection conn) {
closeResultSet(rs);
closeStatement(sta);
closeConnection(conn);
}
}
3、调用存储过程:
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import oracle.jdbc.driver.OracleTypes;
/**
* 测试调用存储过程
*
*/
public class StoredTest {
public static void main(String[] args) {
insert_call();
//select_call();
}
/**
* 执行存储过程 插入数据
*/
public static void insert_call() {
Connection conn = DBUtil.getConnection();
PreparedStatement pst = null;
CallableStatement proc = null; // 创建执行存储过程的对象
try {
proc = conn.prepareCall("{ call insert_procedure(?,?) }");
proc.setString(1, "1"); // 设置第一个输入参数
proc.setString(2, "hello call"); // 设置第一个输入参数
proc.execute();// 执行
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
// 关闭IO流
proc.close();
DBUtil.closeAll(null, pst, conn);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 执行存储过程 查询数据
*/
public static void select_call() {
Connection conn = DBUtil.getConnection();
CallableStatement stmt;
try {
stmt = conn.prepareCall("{ call select_procedure(?, ?) }"); // 用此调用方法不能实现多行语法
stmt.setString(1, "1");
stmt.registerOutParameter(2, OracleTypes.CURSOR);
stmt.execute();
ResultSet rs = (ResultSet) stmt.getObject(2);
while (rs.next()) {
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.closeConnection(conn);
}
}
}