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主要会做一下工作:

  1. 获取目标类上的所有接口列表
  2. 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX;
  3. 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码;
  4. 将对应的字节码转换为对于的class对象;
  5. 创建InvocationHandler实例handler,用来处理Proxy所有方法的调用;
  6. 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的重构话题中;

 

 

posted on   白嫖老郭  阅读(107)  评论(0编辑  收藏  举报

编辑推荐:
· 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代理技术深度解析与实战指南

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示