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 ...
随机推荐
- Redis "MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk"问题的解决(转)
今天第二次遇到Redis “MISCONF Redis is configured to save RDB snapshots, but is currently not able to persis ...
- 78-WS2812-Library (STM32F4)
78-WS2812-Library (STM32F4) //-------------------------------------------------------------- // File ...
- ubuntu下smokeping安装配置
0.参考文件 http://wenku.baidu.com/view/950fbb0a79563c1ec5da71b1 http://aaaxiang000.blog.163.com/blog/sta ...
- 利用阿里云提供的镜像快速更换本地的yum源
打开网页:http://mirrors.aliyun.com/ 从“ 文件列表 ”找到自己的系统: Mirror Last update Help CPAN 2015-07-15 15:36:50 ...
- VS2008 LINK : fatal error LNK1104: cannot open file 'atls.lib'错误解决方案
用VS 2008编写ATL的64位应用程序时,提示链接错误:VS2008 LINK : fatal error LNK1104: cannot open file 'atls.lib' 问题原因 VS ...
- 轮子科技的.NET Core分享
2016年8月11日 应轮子科技一众好友的邀请,在轮子科技给大家做了一个无责任的瞎聊段落,聊聊.NET的Core的一些内容. 恩,演讲者就只有我一个了,讲师是微软的 MVP 杨守斌,就是因为这个,所以 ...
- 使用SQL Database Migration Wizard把SQL Server 2008迁移到Windows Azure SQL Database
本篇体验使用SQL Database Migration Wizard(SQLAzureMW)将SQL Server 2008数据库迁移到 Azure SQL Database.当然,SQLAzure ...
- arcengine Annotation研究的一些学习资料(转)FeatureWeight
转自chanyinhelv原文Annotation研究的一些学习资料 下面是我最近对Annotation研究的一些学习资料,收集于此,供大家学习之用. 一.Annotation要素类介绍 在GeoDa ...
- Java 字符串包含
函数boolean containsAny(String str, String searchChars) 判断str字符串中是否包含searchChars字符串 String khh_str = & ...
- WordPress主题开发:style.css主题信息标记
在最简单的情况下,一个WordPress主题由两个文件构成: index.php ------------------主模版 style.css -------------------主样式表 而且s ...