动态代理在WEB与JDBC开发中的应用(JDBC篇)
来源:互联网 发布:linux glibc 安装 编辑:程序博客网 时间:2024/06/04 19:44
作者:rcom10002
非常感谢原作者!!
背景描述
如果之前看过《动态代理在WEB与JDBC开发中的应用(WEB篇)》,这篇的内容可以全当是另一种应用的进阶举例,而在实现上确实没有太多进步的地方。我们先看一下项目所面临问题以及期望解决方案。在作者所接触的这个项目中,直接使用原始JDBC技术,java.sql.PreparedStatement和java.sql.ResultSet几乎占领了数据访问层,没有半点OR Mapping的迹象,看起来是不是很悲催?命啊~在项目开发至一半的时候,突然发现要对日文字符进行支持,而在之前一直使用英文进行测试。好了,问题来了,一个编码为8859_1的数据库怎么来接收Java中的UTF-8呢?并且很多CRUD功能已经完成,每个实现中涉及的字段数目相当之大,难道针对每个字段逐一调整不成?
问题分析
针对上面描述的情况,我们先做一个简单的分析。目前所面临的问题可以归为两种类型,第一类就是乱码的问题,这个可以通过重新编码得到解决;第二类则是面临大量的代码实现,如果对所有内容进行调整的话,很多功能就得重新测试,成本较高,但确实可行。
针对乱码问题,从实现的角度考虑,可以分别针对输入数据和输出数据进行编码转换。是在使用PreparedStatement的时候,对所有调用setString的地方进行编码转换;而对于数据读取的情况,可以对ResultSet.getString所返回的结果字符串进行编码转换。下面以UTF-8转8859_1为例子,实现编码转换(逆向转换只需交换编码名称的位置即可):
new String(new String("abc").getByte("UTF-8"), "8859_1")如果以这种方式对每处PreparedStatement.setString和ResultSet.getString的调用都进行编码转换操作的话,工作量不仅繁重,而且不利于代码的维护与移植。从API上看,其实我们可以针对setString和getString进行“HOOK”,使用代理模式比较适合,动态代理最为适宜。
解决方案
编码问题解决了,利用动态代理统一地对setString和getString接口进行自制,让所有的调用都在我们的控制之下还何愁不能统一江山!
public static ResultSet createResultSetJPWrapper(ResultSet rs) { return (ResultSet)(Proxy.newProxyInstance(ResultSet.class.getClassLoader(), new Class[] {ResultSet.class}, new ResultSetJPWrapper(rs)));}private static class ResultSetJPWrapper implements InvocationHandler {private ResultSet wrappedResultSet; public ResultSetJPWrapper(ResultSet rs) { wrappedResultSet = rs; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(wrappedResultSet, args); if ("getString".equals(method.getName()) && null != result) { result = CommonUtils.convertCharset((String)result, ISAConstants.CHARSET_8859_1, ISAConstants.CHARSET_UTF_8); } return result; }}public static PreparedStatement createPreparedStatementJPWrapper(PreparedStatement pstmt) { return (PreparedStatement)(Proxy.newProxyInstance(PreparedStatement.class.getClassLoader(), new Class[] {PreparedStatement.class}, new PreparedStatementJPWrapper(pstmt)));}private static class PreparedStatementJPWrapper implements InvocationHandler {private PreparedStatement wrappedStatement; public PreparedStatementJPWrapper(PreparedStatement pstmt) { wrappedStatement = pstmt; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("setString".equals(method.getName()) && args.length == 2 && null != args[1] && String.class.equals(args[1].getClass())) { args[1] = CommonUtils.convertCharset((String)args[1], ISAConstants.CHARSET_UTF_8, ISAConstants.CHARSET_8859_1); } return method.invoke(wrappedStatement, args); }}接下来就是在需要使用PreparedStatement和ResultSet的地方进行重构。
// 重构前PreparedStatement stmt = conn.prepareStatement(sql);// 重构后PreparedStatement stmt = DBUtils.createPreparedStatementJPWrapper(conn.prepareStatement(sql));// 重构前ResultSet rs = stmt.executeQuery();// 重构后ResultSet rs = DBUtils.createResultSetJPWrapper(stmt.executeQuery());
重构后不论是stmt还是rs,setString和getString都会被我们定义的动态代理所劫持,在数据输入前或数据输出后重新编码,而这一切对于开发人员来说一切都是透明的,并且不会对现有逻辑造成污染。
- 动态代理在WEB与JDBC开发中的应用(JDBC篇)
- 动态代理在WEB与JDBC开发中的应用(JDBC篇)
- 动态代理在WEB与JDBC开发中的应用(WEB篇)
- 动态代理在JDBC的DataSource中的应用
- jdbc在web中的应用
- JDBC在Java Web中的应用——分页查询
- 数据源在JDBC中的应用
- 数据源在jdbc中的应用
- 浅谈实际开发中数据源在JDBC中的应用
- 浅谈实际开发中数据源在JDBC中的应用
- MSSQL2000的官方JDBC在应用动态代理机制遇到的异常问题解决
- 使用Servlet+JDBC 开发java web应用
- 浅析数据源在JDBC中的应用
- 浅析数据源在JDBC中的应用
- 数据源在JDBC中的应用-赛迪
- 浅析数据源在JDBC中的应用--1
- 浅析数据源在JDBC中的应用(2)
- 浅析数据源在JDBC中的应用(3)
- c++11之initializer_list
- NestedScrollview 嵌套 RecyclerView 滑动卡顿,ScrollView 嵌套 RecyclerView 冲突 解决方案
- 软工文档
- AsyncTask 源码分析
- 设计模式文章链接
- 动态代理在WEB与JDBC开发中的应用(JDBC篇)
- Support Webpage for Metronome
- 仅通过drawable中的xml文件实现不顶格的分割线
- ss-libev 源码解析udp篇 (4)
- iwpriv 配置 WiFi 的参数含义解说
- liunx 下tomcat启动缓慢的解决方案
- Linux常用命令
- 游戏运行过程中动态改变分辨率和全屏
- ansible自己练习,有点乱