javaweb---重构dao:
原始的jdbc:大致分为
1 注册驱动,获取连接(Connection)
2 获取PreparedStatement||Statement:数据库表CRUD操作对象
3 编写SQL语句
4 执行SQL
5 处理结果:(ResultSet)
6 释放释放
使用Spring提供的jdbctemplate模板构建简化jdbc技术:还是比较复杂,要是SQL逻辑处理的方法很多,那岂不是很恼火。。。。
package cn.edu.cque.mall.dao; import cn.edu.cque.mall.entity.Product; import cn.edu.cque.mall.utils.DruidUtil; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; /** * @ClassName ProductDao * @Description ProductDao * @Author YoungWinter * @Date 2020/9/22 14:17 * @Version 1.0 **/ public class ProductDao { private JdbcTemplate template = new JdbcTemplate(DruidUtil.getDataSource()); // 将数据库中的数据封装成实体类的一个内部类 private class ProductRowMapper implements RowMapper<Product> { @Override public Product mapRow(ResultSet rs, int rowNum) throws SQLException { Product product = new Product(); product.setId(rs.getString("pid")); product.setName(rs.getString("pname")); product.setMarketPrice(rs.getDouble("market_price")); product.setShopPrice(rs.getDouble("shop_price")); product.setImage("http://192.168.11.44:9090" + rs.getString("pimage")); product.setCreateDate(rs.getDate("pdate")); product.setIsHot(rs.getInt("is_hot")); product.setDesc(rs.getString("pdesc")); product.setFlag(rs.getInt("pflag")); product.setCid(rs.getString("cid")); return product; } } /*** * @Author YoungWinter * @Description 根据id查询数据 * @Date 10:45 2020/9/23 * @Param [id] * @return java.util.List<cn.edu.cque.mall.entity.Product> **/ public List<Product> findById(String id) { // 1 获取连接 // 2 获取ps // 3 编写SQL语句 // 4 执行SQL // 5 处理结果 // 6 释放释放 return template.query("select * from product where pid = ?", new ProductRowMapper(), id); } /*** * @Author YoungWinter * @Description 查询总记录数 * @Date 9:16 2020/9/23 * @Param [] * @return int **/ public int findTotalNumber(String cid) { return template.queryForObject("select count(*) from product where cid = ?", int.class, cid); } /*** * @Author YoungWinter * @Description 根据cid和分页信息查询商品列表 * @Date 9:12 2020/9/23 * @Param [cid, index, pageSize] * @return java.util.List<cn.edu.cque.mall.entity.Product> **/ public List<Product> findListByCidAndPage(String cid, int index, int pageSize) { return template.query("select * from product where cid = ? limit ?, ?", new ProductRowMapper(), cid, index, pageSize); } /*** * @Author YoungWinter * @Description 查询热销商品 * @Date 15:29 2020/9/22 * @Param [] * @return java.util.List<cn.edu.cque.mall.entity.Product> **/ public List<Product> findHot() { String sql = "select * from product where is_hot = ? limit ?, ?"; return template.query(sql, new ProductRowMapper(), 1, 0, 8); } /*** * @Author YoungWinter * @Description 查询最新商品 * @Date 15:29 2020/9/22 * @Param [] * @return java.util.List<cn.edu.cque.mall.entity.Product> **/ public List<Product> findNews() { String sql = "select * from product order by pdate desc limit ?, ?"; return template.query(sql, new ProductRowMapper(), 0, 8); } /*** * @Author YoungWinter * @Description 根据cid查询商品列表 * @Date 15:30 2020/9/22 * @Param [cid] * @return java.util.List<cn.edu.cque.mall.entity.Product> **/ public List<Product> findListByCid(String cid) { String sql = "select * from product where cid = ?"; return template.query(sql, new ProductRowMapper(), cid); } }
如何让这个界面更加简洁,功能更加职责化。。。大量的重复的部分可以抽取。。。。么。。。
比如就写一个方法,一句SQL就可以达到效果,。。。。操作数据库。。。。得到结果集。。
比如这样的:效果和那负责的原始的jdbctemlate一样:
package cn.edu.cque.mall.mapper; import cn.edu.cque.mall.common.Sql; import cn.edu.cque.mall.entity.Product; import java.util.List; /** * @ClassName ProductMapper * @Description TODO * @Author YoungWinter * @Date 2020/9/23 16:33 * @Version 1.0 **/ public interface ProductMapper { @Sql("select * from product where pid = ?") Product findById(String id); @Sql("select count(*) from product where cid = ?") int findTotalNumber(String cid); @Sql("select * from product where cid = ? limit ?, ?") List<Product> findListByCidAndPage(String cid, int index, int pageSize); @Sql("select * from product where is_hot = ? limit ?, ?") List<Product> findHot(int isHot, int index, int size); @Sql("select * from product order by pdate desc limit ?, ?") List<Product> findNews(int isHot, int index, int size); @Sql("select * from product where cid = ?") List<Product> findListByCid(String cid); }
分析不同点“简化:让一个注解sql加上方法实现功能。。。。。。”
一步一步来:
注解,,那需要自己定义一个:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Path { String value(); }
那我一个接口的方法,凭什么会可以实现sql业务需求呢。。。。。怎么解决。。。这里了解23种设计模式中的代理模式,增强方法。。。
代理模式实现方式两种:jdk支持的proxy。。。。还有第三方的cglib。。。
利用代理模式代理对象实现具体的业务逻辑处理。。。。。
这里聊一聊代理模式。。。。。
Jdk动态代理:
Jdk的动态代理是基于接口的。现在想要为目标类创建一个动态代理对象,Jdk主要会做一下工作:
- 获取目标类上的所有接口列表
- 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX;
- 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
- 将对应的字节码转换为对于的class对象;
- 创建InvocationHandler实例handler,用来处理Proxy所有方法的调用;
- Proxy的class对象以创建的handler对象为参数,实例化一个proxy对象;
Jdk通过java.lang.reflect.Proxy包来支持动态代理,在Java中要创建一个代理对象,必须调用Proxy类的静态方法newProxyInstance,该方法的原型如下:
Object Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException
其中:
loader,表示类加载器,
interfaces,表示接口,就是前述代理对象和真实对象都必须共有的父类或者接口;
handler,表示调用处理器,它必须是实现了InvocationHandler接口的对象,
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
其中:
proxy,表示执行这个方法的代理对象;
method,表示真实对象实际需要执行的方法(关于Method类参见Java的反射机制);
args,表示真实对象实际执行方法时所需的参数。
在实际的编程中,需要优先定义一个实现InvocationHandler接口的调用处理器对象,然后将它作为创建代理类实例的参数。(抑或在调用newProxyInstance方法时使用匿名内部类。)这样就得到了代理对象。
真实对象本身的实例化在调用处理器对象内部完成,实例化时需要的参数也应该及时传入调用处理器对象中。这样一来就完成了代理对象对真实对象的包装,而代理对象需要执行的额外操作也在invoke方法中处理。
其后,在客户端中,如果需要使用真实对象时,就可以用代理对象来替代它了(有时需要类型强制转化)。
:第一步目标对象》》》》》
public class Cat implements Sayable{ public void say() { System.out.println("小猫喵喵喵"); } }
:第二步目标对象的接口》》》》
public interface Sayable { void say(); }
:第三步实现InvocationHandler接口的调用处理器对象:这个处理器对象需要目标对象。。
public class SayHandle implements InvocationHandler { private Object target; public SayHandle(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("增强小猫的say()"); method.invoke(target); return null; } }
:第四步生成动态代理对象》》》》
Cat cat = new Cat(); // 使用下面特定的方法创建cat的代理对象 /** * ClassLoader loader,被代理对象所属的类的类加载器 * Class<?>[] interfaces,被代理对象所属的类实现的接口 * InvocationHandler h 增强的处理器,里面有对方法增强的代码 **/ Sayable catProxy = (Sayable) Proxy.newProxyInstance(cat.getClass().getClassLoader(), new Class[]{Sayable.class}, new SayHandle(cat)); catProxy.say();
现在明白了proxy动态代理。。。。。。。然后回到dao的重构话题中;
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
Java入门到入坟
万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南