Sql控制反转小尝试
假想用配置Sql语句的方式来完毕一个处理逻辑,而且映射到一个Url,这样当请求这个url的时候,运行前面配置的sql。
以下的一段详细配置,比如 当请求pagerlistdept.do的时候,会传入參数Offset,并调用handler运行里面配置的SQL语句。
dept_sql_mapping.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- <!DOCTYPE sql-mappings SYSTEM "sql-parser.dtd"> -->
<sql-mappings>
<sql-mapping url="pagerlistdept.do" success="/deptlist.jsp" fail="/error.jsp" handler="org.sqlparser.handler.impl.SimpleSqlHandler">
<sql result="deptlist" type="query" variables="offset">
select d.id_f,d.name_f,count(e.id_f) emp_count from dept_t d left join emp_t e
on d.id_f=e.dept_id_f group by d.id_f limit #offset#,6
</sql>
<sql result="dept_count" type="count">
select count(*) from dept_t
</sql>
</sql-mapping>
<sql-mapping url="deptlist.do" success="/deptlist.jsp">
<sql result="deptlist" type="query">
select d.id_f,d.name_f,count(e.id_f) emp_count from dept_t d left join emp_t e
on d.id_f=e.dept_id_f group by d.id_f limit 0,6
</sql>
<sql result="dept_count" type="count">
select count(*) from dept_t
</sql>
</sql-mapping>
<sql-mapping url="jsondeptlist.do" type="json">
<sql result="deptlist" type="query">
select * from dept_t
</sql>
</sql-mapping>
<sql-mapping url="deptedit.do" success="deptadd.jsp">
<sql result="dept" type="find">
select id_f,name_f from dept_t where id_f=#did#
</sql>
</sql-mapping>
<sql-mapping url="deptadd.do" success="deptlist.do" fail="/error.jsp">
<sql result="added_rows" type="update">
insert into dept_t(name_f) values('#name#')
</sql>
<validate>
<parameter name="name" validator="org.sqlparser.validator.impl.AccountValidator"/>
</validate>
</sql-mapping>
<sql-mapping url="deptdelete.do" success="deptlist.do" fail="/error.jsp">
<transactional>
<sql type="update">delete from dept_t where id_f=#did#</sql>
</transactional>
</sql-mapping>
<sql-mapping url="deptupdate.do" success="deptlist.do">
<sql type="update">
update dept_t set name_f='#name#' where id_f=#did#
</sql>
</sql-mapping>
</sql-mappings>
以下看看怎么实现。。。
首先。在classpath以下定义一个总的配置文件,临时命名为sqlparser.xml,定义好默认的handler和数据库连接信息(db.properties)
<?xml version="1.0" encoding="UTF-8"?>
<sqlparser>
<mapping name="dept_mapping" location="mappings/dept_sql_mapping.xml"/>
<default-sql-handler class="org.sqlparser.handler.impl.SimpleSqlHandler"/>
<database-config-file file="db.properties"/>
</sqlparser>
创建总的控制器,用一个Servlet来完毕。
主要用于载入配置信息,拦截请求并解析
/**
* Dispacher servlet for sqlparser
* You should configure this servlet as normal servlet int web.xml
* and set <load-on-startup>1</load-on-startup> to make
* it starts with web container
* @author john.liu
*
*/
public class SqlParserServlet extends HttpServlet {
private static final long serialVersionUID = 1L; protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
request.setCharacterEncoding("UTF-8");
request.removeAttribute("VALIDATION_ERRORS");
request.getSession().removeAttribute("ERRORS");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
RequestParser rp = new RequestParser(request,response);
rp.parse();
}
@Override
public void init(ServletConfig config) throws ServletException {
long st = System.currentTimeMillis();
ConfigurationParser.loadConfiguration();
long ed = System.currentTimeMillis();
System.out.println("load configurations in "+(ed-st)+" ms.");
}
}
载入配置信息由RequestParser完毕,这里面主要是依据请求的uri获取到处理的handler和sql语句,运行并分发视图.
/**
* Class for parsing request
* This is almost heart of sqlparser,which parses request,executes sql,dispatches result,returns error.
* @author john.liu
*
*/
public class RequestParser {
private HttpServletRequest request;
private HttpServletResponse response;
private String request_do;
/**
* 404 request target
*/
private String success = "404error.do";
/**
* error request target
*/
private String fail = "error.do";
/**
* specify type='json' to make an ajax request
*/
private String type;
/**
* by default ,redirect is false
*/
private boolean redirect = false;
private SqlBean[] sql_array;
private SqlBean[] tran_sql_array;
private HashMap<String,String> parameters;
private SqlHandler default_sql_handler; public RequestParser(HttpServletRequest request,HttpServletResponse response){
this.request = request;
this.response = response;
init();
}
/**
* initiate some variables by request
*/
private void init(){
String uri = request.getRequestURI();
String context = request.getContextPath();
this.request_do = uri.substring(uri.indexOf(context)+context.length()+1);
if(request_do.indexOf("? ")!=-1)
this.request_do = request_do.substring(0, request_do.indexOf("?")); HashMap url_map = ConfigurationParser.sqlMap.get(request_do);
if(url_map == null) {
this.request_do = "404error.do";
}
boolean isError = handleErrorRequest();
if(isError) return; type = url_map.get("TYPE")!=null? (String)url_map.get("TYPE"):null;
success = url_map.get("SUCCESS")!=null?(String)url_map.get("SUCCESS"):success;
fail = url_map.get("FAIL")!=null?(String)url_map.get("FAIL"):fail;
redirect = url_map.get("REDIRECT")!=null?Boolean.valueOf((String)url_map.get("REDIRECT")):false;
sql_array = url_map.get("SQL_ARRAY")!=null?(SqlBean[])url_map.get("SQL_ARRAY"):null;
tran_sql_array = url_map.get("TRAN_SQL_ARRAY")!=null? (SqlBean[])url_map.get("TRAN_SQL_ARRAY"):null;
parameters = url_map.get("VALIDATE_PARAM")!=null? (HashMap<String,String>)url_map.get("VALIDATE_PARAM"):null;
String handler_class = url_map.get("SQL_HANDLER")!=null?url_map.get("SQL_HANDLER").toString():null; initHandlerClass(handler_class); //initiate handler class
} private void initHandlerClass(String handler_class) {
try {
long st = System.currentTimeMillis();
if(default_sql_handler != null && default_sql_handler.getClass().getCanonicalName().equals(handler_class)){
//dont initialize the same handler
return;
}
if(handler_class!=null){
Class<SqlHandler> clazz = (Class<SqlHandler>)Class.forName(handler_class);
default_sql_handler = clazz.newInstance();
}else if(ConfigurationParser.default_sql_handler_class!=null){
Class<SqlHandler> clazz = (Class<SqlHandler>)Class.forName(ConfigurationParser.default_sql_handler_class);
default_sql_handler = clazz.newInstance();
}else{
default_sql_handler = new SimpleSqlHandler(ConfigurationParser.db_config_file);
}
long ed = System.currentTimeMillis();
System.out.println("["+new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date())+"]"+default_sql_handler.toString()+" cost: "+(ed-st)+" ms");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* pasrse request
*/
public void parse() {
if(default_sql_handler==null) return;
if(default_sql_handler.getConnection()==null) default_sql_handler.openConnection(); if(ConfigurationParser.sqlMap.get(success)!=null){
redirect = true; //redirect to another request in the url-map
}
List<String> errors = ReuqestParameterValidator.doValidate(request,parameters); //do validation
if(errors.size()>0){
try {
//validate error
if(type!=null&&(type.equals("json")||type.equals("xml"))){
PrintWriter pw = response.getWriter();
pw.write("false");
pw.close();
}else{
request.setAttribute("VALIDATION_ERRORS", errors);
request.getRequestDispatcher(fail).forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
}
}else{
//no error with validation,dispatch result
distrubuteResult();
}
}
/**
* handle errors
* @return
*/
private boolean handleErrorRequest() {
if(!request_do.equals("error.do")&&!request_do.equals("404error.do")) return false;
String url = "";
if(request_do.equals("error.do")){
url = "/WEB-INF/classes/web/error.jsp";
}else if(request_do.equals("404error.do")){
url = "/WEB-INF/classes/web/404.jsp";
}
try {
request.getRequestDispatcher(url).forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
/**
* dispatche result
*/
private void distrubuteResult() {
try{
response.setCharacterEncoding("UTF-8");
default_sql_handler.getErrors().clear();
HashMap<String,Object> resultMap = getSqlResult();
if(type!=null&&(type.equals("json"))){
PrintWriter pw = response.getWriter();
JSONObject jo = JSONObject.fromObject(resultMap);
pw.write(jo.toString());
pw.close();
}else{
if(default_sql_handler.getErrors().size()>0){
//sql execute error
request.getSession().setAttribute("ERRORS", default_sql_handler.getErrors());
//response.sendRedirect(request.getContextPath()+""+fail);
response.sendRedirect(request.getContextPath()+"/"+fail);
}else{
if(redirect){
response.sendRedirect(request.getContextPath()+"/"+success);
}else{
request.getRequestDispatcher(success).forward(request, response);
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally{
default_sql_handler.closeConnection(); //close current connection
}
}
/**
* execute sql, and return result map
* @return result map
* @throws SQLException
*/
private HashMap<String,Object> getSqlResult() throws SQLException {
HashMap<String,Object> resultMap = new HashMap<String, Object>(0);
if(sql_array!=null){
for(SqlBean sql:sql_array){
Object res = executeSql(sql);
if(type!=null&&(type.equals("json"))){
resultMap.put(sql.getResult(), res);
}
}
}
if(tran_sql_array!=null){
if(default_sql_handler.getConnection()==null) default_sql_handler.openConnection();
default_sql_handler.getConnection().setAutoCommit(false);
for(SqlBean tran_sql:tran_sql_array){
Object res = executeSql(tran_sql);
if(type!=null&&(type.equals("json"))){
resultMap.put(tran_sql.getResult(), res);
}
}
default_sql_handler.getConnection().commit();
}
return resultMap;
}
/**
* execute single sql
* @param sqlbean
* @return mixed type object probably are int,object[] or list<object[]>
* @throws SQLException
*/
private Object executeSql(SqlBean sqlbean) throws SQLException{
String sql = sqlbean.getSql();
sql = setSqlParameters(sql); //set parameter
String result = sqlbean.getResult();
String type = sqlbean.getType();
String[] variables = sqlbean.getVariables();
Object res = null;
if("update".equals(type)){
int rows = 0;
try {
rows = default_sql_handler.update(sql);
} catch (SQLException e) {
default_sql_handler.rollback();
System.err.println("[sql execute error]"+sql);
default_sql_handler.setError("[sql execute error]");
}
res = rows;
}else if("query".equals(type)){
if(result==null) return null;
res = default_sql_handler.query(sql);
}else if("find".equals(type)){
if(result==null) return null;
res = default_sql_handler.find(sql);
}else if("count".equals(type)){
if(result==null) return 0;
res = default_sql_handler.count(sql);
}
HttpSession session = request.getSession();
if(result != null){
if(redirect){
session.setAttribute(result, res);
}else{
request.setAttribute(result, res);
}
}
if(variables != null){
for(String var:variables){
if(redirect){
session.setAttribute(var, request.getParameter(var));
}else{
request.setAttribute(var, request.getParameter(var));
}
}
}
return res;
}
private String setSqlParameters(String sql){
Pattern p = Pattern.compile("#(\\w|\\d)+#");
Matcher m = p.matcher(sql);
while(m.find()){
String g = m.group();
String param = g.replace("#", "");
sql = sql.replace(g, escapeString(request.getParameter(param)));
}
return sql;
} private static String escapeString(String str){
if(str==null) return "null";
return str.replace("\'", "\\'").replace("\"", "\\\"").replaceAll("\\s+or\\s+", " or ");
}
SimpleSqlHandler类定义增改删查之类的方法
package org.sqlparser.handler.impl; import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties; import org.sqlparser.handler.SqlHandler;
/**
* <p>Simple implementation of sql handler</p>
* <p>This class defined the simplest jdbc operations,which are query,count,find,update</p>
* <p>You can make your owner sql handler by implementing interface SqlHandler</p>
* <p>The best way is defining a default sql handler by implementing interface SqlHandler ,
* and implementing all methods.Then if needed, you can define other handlers by
* extending the default sql handler you defined before, and override one or more methods
* according to your detail logic.And these handlers can be sepecified in 'handler' attribute
* of sql-mapping to make this sql-mapping request handled by your owner sql handler.</p>
* @author john.liu
*
*/
public class SimpleSqlHandler implements SqlHandler {
private String configFile = "db.properties";
/**
* Connection
*/
private Connection conn;
/**
* PreparedStatement
*/
private PreparedStatement pstmt;
/**
* Database driver class
* <p>It is suggested that u make this property configured in a file
* and configure 'database-config-file' attribute in sqlparser.xml</p>
*/
private static String db_driver;
/**
* Database connection url
* <p>It is suggested that u make this property configured in a file
* and configure 'database-config-file' attribute in sqlparser.xml</p>
*/
private static String db_url;
/**
* Database user name
* <p>It is suggested that u make this property configured in a file
* and configure 'database-config-file' attribute in sqlparser.xml</p>
*/
private static String db_user;
/**
* database connect password
* <p>It is suggested that u make this property configured in a file
* and configure 'database-config-file' attribute in sqlparser.xml</p>
*/
private static String db_password;
/**
* Default constructor method
*/
public SimpleSqlHandler(){
init();
}
/**
* Constructor method
* <p>Initiate an instance by specified database configure file
* @param config_file
*/
public SimpleSqlHandler(String config_file){
if(config_file != null && !"".equals(configFile)) {
this.configFile = config_file;
}
init();
}
/**
* Load database configure file
* @param config_file database configure file
*/
private void init() { Properties props = new Properties();
try {
props.load(this.getClass().getClassLoader().getResourceAsStream(this.configFile));
db_driver = props.getProperty("db_driver");
db_url = props.getProperty("db_url");
db_user = props.getProperty("db_user");
db_password = props.getProperty("db_password");
} catch (IOException e) {
e.printStackTrace();
setError("can not load database config file");
}
}
/**
* Open a new connection if connection is null
*/
@Override
public void openConnection(){
if(conn != null) return;
try {
Class.forName(db_driver);
conn = DriverManager.getConnection(db_url,db_user,db_password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* Close connection if connection is not null
*/
@Override
public void closeConnection() {
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* Get a connection
*/
@Override
public Connection getConnection() {
return this.conn;
}
/**
* Execute update
*/
@Override
public int update(String sql) throws SQLException{
openConnection();
pstmt = conn.prepareStatement(sql);
return pstmt.executeUpdate();
}
/**
* Execute select, return result set row number
*/
@Override
public int count(String sql) {
try {
openConnection();
pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
if(rs.next()){
return rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
/**
* Execute select, return one row data
*/
@Override
public Object[] find(String sql) {
try {
openConnection();
pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
int cols = rs.getMetaData().getColumnCount();
Object[] row = new Object[cols];
if(rs.next()){
for(int loop=0; loop<cols; loop++){
row[loop] = rs.getObject(loop+1);
}
}
return row;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* Execute select, return a data list.
* <p>Use row index and column index to retrieve items in data list</p>
*/
@Override
public List<Object[]> query(String sql) {
try {
openConnection();
pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
int cols = rs.getMetaData().getColumnCount();
ArrayList<Object[]> list = new ArrayList<Object[]>(0);
while(rs.next()){
Object[] row = new Object[cols];
for(int loop=0; loop<cols; loop++){
row[loop] = rs.getObject(loop+1);
}
list.add(row);
}
return list;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* Roll back current transaction
* <p>You can put some <sql> tags in <transactional> to make these sql executed
* within a transaction,either of these sql 's failure will cause this method 's invoke</p>
*/
@Override
public void rollback() {
try {
if(!conn.getAutoCommit())
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* Put an error to error list
*/
@Override
public void setError(String error) {
errors.add(error);
}
/**
* Get error list return by this handler instance
*/
@Override
public ArrayList<String> getErrors() {
return errors;
}
}
Sql控制反转小尝试的更多相关文章
- 码农小汪-spring框架学习之2-spring IoC and Beans 控制反转 依赖注入 ApplicationContext BeanFactory
spring Ioc依赖注入控制反转 事实上这个东西很好理解的,并非那么的复杂. 当某个Java对象,须要调用还有一个Java对象的时候(被依赖的对象)的方法时.曾经我们的做法是怎么做呢?主动的去创建 ...
- Java 控制反转和依赖注入模式【翻译】【整理】
Inversion of Control Containers and the Dependency Injection pattern --Martin Fowler 本文内容 Component ...
- spring框架篇(一)-------spring简介与配置文件使用控制反转事例
spring简介 Spring 是一个开源框架,中文意思就是春天,也许是作者想让自己的这个框架给Java开发人员带来春天吧.其官方网站是 https://spring.io/ ,可以在官方网站下载到完 ...
- Spring理论基础-控制反转和依赖注入
第一次了解到控制反转(Inversion of Control)这个概念,是在学习Spring框架的时候.IOC和AOP作为Spring的两大特征,自然是要去好好学学的.而依赖注入(Dependenc ...
- Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用
一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...
- 浅谈(IOC)依赖注入与控制反转(DI)
前言:参考了百度文献和https://www.cnblogs.com/liuqifeng/p/11077592.html以及http://www.cnblogs.com/leoo2sk/archive ...
- 一统江湖的大前端(10)——inversify.js控制反转
<大史住在大前端>前端技术博文集可在下列地址访问: [github总基地][博客园][华为云社区][掘金] 字节跳动幸福里大前端团队邀请各路高手前来玩耍,团队和谐有爱,技术硬核,字节范儿正 ...
- .Net Core MVC 网站开发(Ninesky) 2.3、项目架构调整-控制反转和依赖注入的使用
再次调整项目架构是因为和群友dezhou的一次聊天,我原来的想法是项目尽量做简单点别搞太复杂了,仅使用了DbContext的注入,其他的也没有写接口耦合度很高.和dezhou聊过之后我仔细考虑了一下, ...
- 小菜学习设计模式(五)—控制反转(Ioc)
写在前面 设计模式目录: 小菜学习设计模式(一)—模板方法(Template)模式 小菜学习设计模式(二)—单例(Singleton)模式 小菜学习设计模式(三)—工厂方法(Factory Metho ...
随机推荐
- bitnami-redmine邮件告警配置
配置 bitnami-redmine的配置文件与单纯的redmine配置文件可能并不相同,在这里我们需要打开一下配置文件: /opt/bitnami/apps/redmine/htdocs/confi ...
- 《Go学习笔记 . 雨痕》类型
一.基本类型 清晰完备的预定义基础类型,使得开发跨平台应用时无须过多考虑符合和长度差异. 类型 长度 默认值 说明 bool 1 false byte 1 0 uint8 int, uint 4, ...
- How to update WPF browser application manifest and xbap file with ‘mage.exe’
老外参考文章1 老外参考文章2 I created a WPF browser application MyApp then published it by ClickOnce in VS2008. ...
- 前端使用AngularJS的$resource,后端ASP.NET Web API,实现增删改查
AngularJS中的$resource服务相比$http服务更适合与RESTful服务进行交互.本篇后端使用ASP.NET Web API, 前端使用$resource,实现增删改查. 本系列包括: ...
- 关于Maven项目build时出现No compiler is provided in this environment的处理(转)
本文转自https://blog.csdn.net/lslk9898/article/details/73836745 近日有同事遇到在编译Maven项目时出现[ERROR] No compiler ...
- Android 实时视频编码—H.264硬编码
from://http://www.cnblogs.com/skyseraph/archive/2012/04/04/2431771.html 1 硬编码 & 软编码 硬编码:通过调用And ...
- netty 支持多种通讯协议
通讯协议,指的是把Netty通讯管道中的二进制流转换为对象.把对象转换成二进制流的过程.转换过程追根究底还是ChannelInboundHandler.ChannelOutboundHandler的实 ...
- 快速排序原理及Java实现
1.基本思想: 快速排序是我们之前学习的冒泡排序的升级,他们都属于交换类排序,都是采用不断的比较和移动来实现排序的.快速排序是一种非常高效的排序算法,它的实现,增大了记录的比较和移动的距离,将关键字较 ...
- “finally block does not complete normally”的警告解决
但是,java里面不是可以保证finally一定会执行的么,为什么不可以在finally块做return??? 细细看道来: debug一下这个函数,就会惊讶的发现, 里面抛出的异常会被finally ...
- 得到view坐标的各种方法
这篇文章讲的方法全是再控件可以获取焦点的情况下执行的,如果在oncreat()里面执行,那么得到的都是0 1.getLocationInWindow 这个方法得到的是view相对于当前Activity ...