新手入门之模糊查询与封装请求参数和返回参数

题外话:预计进度失误,发现这个知识点也是有必要总结一下,争取双更o(╥﹏╥)o

为方便大家跟着笔者做出来,每步代码齐全,请放心食用!

Generator生成器

上一节我们手写了mybaties框架实现查询,这一节我们使用generator生成器集成mybaties框架,这个想必大家都会,简单复习一下

1.建张数据库表(附sql语句)

drop table if exists `ebook`;
create table `ebook` (
  `id` bigint not null comment 'id',
  `name` varchar(50) comment '名称',
  `category1_id` bigint comment '分类1',
  `category2_id` bigint comment '分类2',
  `description` varchar(200) comment '描述',
  `cover` varchar(200) comment '封面',
  `doc_count` int not null default 0 comment '文档数',
  `view_count` int not null default 0 comment '阅读数',
  `vote_count` int not null default 0 comment '点赞数',
  primary key (`id`)
) engine=innodb default charset=utf8mb4 comment='电子书';

insert into `ebook` (id, name, description) values (1, 'Spring Boot 入门教程', '零基础入门 Java 开发,企业级应用开发最佳首选框架');
insert into `ebook` (id, name, description) values (2, 'Vue 入门教程', '零基础入门 Vue 开发,企业级应用开发最佳首选框架');
insert into `ebook` (id, name, description) values (3, 'Python 入门教程', '零基础入门 Python 开发,企业级应用开发最佳首选框架');
insert into `ebook` (id, name, description) values (4, 'Mysql 入门教程', '零基础入门 Mysql 开发,企业级应用开发最佳首选框架');
insert into `ebook` (id, name, description) values (5, 'Oracle 入门教程', '零基础入门 Oracle 开发,企业级应用开发最佳首选框架');

2.Pom文件引入依赖(放在</plugins>上面,版本如果报错就换你有的)

 <!-- mybatis generator 自动生成代码插件 -->
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.4.0</version>
                <configuration>
                    <configurationFile>src/main/resources/generator/generator-config.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.22</version>
                    </dependency>
                </dependencies>
            </plugin>

application.properties中配置xml路径

mybatis.mapper-locations=classpath:/mapper/**/*.xml

3.在resource下新建generator包,命名generator-config.xml文件,代码如下,按照自己domain类,mapperxml,mapper类的位置设置,jdbcConnection改成自己数据库

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <context id="Mysql" targetRuntime="MyBatis3" defaultModelType="flat">

        <!-- 自动检查关键字,为关键字增加反引号 -->
        <property name="autoDelimitKeywords" value="true"/>
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        <!--覆盖生成XML文件-->
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
        <!-- 生成的实体类添加toString()方法 -->
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"/>

        <!-- 不生成注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://127.0.0.1:3306/book?serverTimezone=Asia/Shanghai"
                        userId="admin"
                        password="123456">
        </jdbcConnection>

        <!-- domain类的位置 -->
        <javaModelGenerator targetProject="src\main\java"
                            targetPackage="com.zhy.ebook.demos.domain"/>

        <!-- mapper xml的位置 -->
        <sqlMapGenerator targetProject="src\main\resources"
                         targetPackage="mapper"/>

        <!-- mapper类的位置 -->
        <javaClientGenerator targetProject="src\main\java"
                             targetPackage="com.zhy.ebook.demos.mapper"
                             type="XMLMAPPER"/>


        <table tableName="ebook"/>
     
    </context>
</generatorConfiguration>

4.点开右边工具栏的maven,运行生成器

接着你就可以发现多了四个文件分别是domain下的Ebook EbookExample  mapper下的EbookMapper类和mapper下的EbookMapper.xml,你可能会好奇EbookExample的用途,接着往下看吧

5.需求是依然是查询图书列表,简单进行一下Service,Controller的处理就ok了,小伙伴可以运行一下

@Service
public class EbookService {
    @Resource
    //Resource和Autowired都可以将mapper注入
    private EbookMapper EbookMapper;
    public List<Ebook> list(){
        return EbookMapper.selectByExample(null);
    }
}
@RestController
@RequestMapping("/ebook")
public class EbookController {
    @Resource
    private EbookService EbookService;
    @GetMapping("/list")
    public List<Ebook> EbookList(){
        return EbookService.list();
    }
}

模糊查询

我们想采用关键词搜索某条数据,比如我们用图书名字(name)作为查询条件,那么我们应该怎么做?

1.前端发出的请求携带用户输入的name参数,以name是Spring为例

GET http://localhost:8080/ebook/list?name=Spring

2.Controller层接收String参数

public List<Ebook> EbookList(String name)
 List<Ebook> list=EbookService.list(name);

3.Service层用EbookExample类自带的createCriteria函数进行模糊查询

@Service
public class EbookService {
    @Resource
    //Resource和Autowired都可以将mapper注入
    private EbookMapper EbookMapper;
    public List<Ebook> list(String name){
        //ebookExample相当于一个查询条件的对象,之前写为null代表*
        EbookExample ebookExample = new EbookExample();
        EbookExample.Criteria criteria = ebookExample.createCriteria();
        //以上两句为固定方法用于模糊查询
        //查询
        criteria.andNameLike("%"+name+"%");
}
        return EbookMapper.selectByExample(ebookExample);
    }
      

到这为止就结束了,是不是特别简单,测试一下,结果确实是只查询出一条语句
 

封装请求参数

上述我们只是带了个name参数,如果我们还想带上id,docCount等是不是写起来特别麻烦,所以我们将所有的请求参数封装成一个类。

1.新建个req包,新建个EbookReq类,我们将Ebook实体类进行复制,比如我们只想传递id,name参数,就把别的参数去掉,如下

public class EbookReq {
    private Long id;

    private String name;



    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", id=").append(id);
        sb.append(", name=").append(name);
         sb.append("]");
        return sb.toString();
    }
}

2.Controller层接收EbookReq对象,有了前面的铺垫想必你可以很轻松的写出来

public List<Ebook> EbookList(EbookReq req)
 List<Ebook> list=EbookService.list(req);

3.Service层进行相应改动就ok了,测试结果也是相同的


public class EbookService {
    @Resource
    //Resource和Autowired都可以将mapper注入
    private EbookMapper EbookMapper;
    public List<Ebook> list(EbookReq req){
        //ebookExample相当于一个查询条件的对象,之前写为null代表*
        EbookExample ebookExample = new EbookExample();
        EbookExample.Criteria criteria = ebookExample.createCriteria();
        //以上两句为固定方法用于模糊查询
        //查询
        criteria.andNameLike("%"+req.getName()+"%");
}
        return EbookMapper.selectByExample(ebookExample);
    }
      

封装返回参数(二次封装)

首先前端发出请求,我们只有直接返回数据和报错两种可能,但是我们想给前端一些统一的提示,如果请求成功,我们就success并且返回data数据,如果请求失败,我们也给予他一些错误提示

新建包名为Resp,新建CommonResp类,模版如下。(想必小伙伴也能看出取名的意思,Request是请求参数,Response是响应数据)

public class CommonResp<T> {

    /**
     * 业务上的成功或失败
     */
    private boolean success = true;

    /**
     * 返回信息
     */
    private String message;

    /**
     * 返回泛型数据,自定义类型
     */
    private T content;

    public boolean getSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getContent() {
        return content;
    }

    public void setContent(T content) {
        this.content = content;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("ResponseDto{");
        sb.append("success=").append(success);
        sb.append(", message='").append(message).append('\'');
        sb.append(", content=").append(content);
        sb.append('}');
        return sb.toString();
    }
}

稍微修改一下Controller层,就是将原本的返回值赋值为resp的setContent属性

@RestController
@RequestMapping("/ebook")
public class EbookController {
    @Resource
    private EbookService EbookService;
   
    @GetMapping("/list")
    public CommonResp EbookList(EbookReq req){
        CommonResp<List<Ebook>> resp=new CommonResp<>();
        List<Ebook> list=EbookService.list(req);
        resp.setContent(list);
        return resp;
    }
}

运行一遍,可以看到success,message这些都是我们新加的属性

现在我们思考一个问题,我们能够将整个数据库对应的实体类ebook直接暴露出来吗,这样一些敏感字段很容易被爬虫获取导致数据泄露,还有前端不需要的字段我们也不需要传给他,我们为了保护实体类,应该专门在封装一个返回类。

1.我们这里的返回类放到Resp软件包下直接复制ebook类未更改(小伙伴也可以自行更改尝试)名称为EbookResp,这里就无需贴图了,与ebook类内容一致

2.修改Controller层将Ebook改为EbookResp

  @GetMapping("/list")
    public CommonResp EbookList(EbookReq req){
        //用CommonResp对返回信息进行二次封装,主要是添加响应成功/失败的提示等
        CommonResp<List<EbookResp>> resp=new CommonResp<>();
        //此时里面的Service返回的对象就变成了EbookResp
        List<EbookResp> list=EbookService.list(req);
        resp.setContent(list);
        return resp;
    }

3.修改Service层,每一步都写了注释,主要是进行一个集合的复制过程

  public List<EbookResp> list(EbookReq req){
        //ebookExample相当于一个查询条件的对象,之前写为null代表*
        EbookExample ebookExample = new EbookExample();
        EbookExample.Criteria criteria = ebookExample.createCriteria();
        //以上为固定方法用于模糊查询
        criteria.andNameLike("%"+req.getName()+"%");

        List<Ebook> ebookList = EbookMapper.selectByExample(ebookExample);
        //我们现在要做的是将list<Ebook>转化成list<EbookResp>,也就是进行集合的复制

        //创建一个返回结果的实例
        List<EbookResp> respList=new ArrayList<>();

        //循环集合中的每个对象进行复制
        for(Ebook ebook :ebookList){
            //一个ebookResp对应接收一个ebook
            EbookResp ebookResp = new EbookResp();
//            ebookResp.setId(ebook.getId());
            //如果按以上做法手写完成每个属性的拷贝是非常麻烦的,BeanUtils工具可以直接完成对象的复制
            BeanUtils.copyProperties(ebook,ebookResp);
            //将对象一一添加到集合里
            respList.add(ebookResp);

        }
        return respList;
    }

运行一遍没有问题

我们思考每次写Service函数都要写一遍集合浅克隆或者对象浅克隆是不是太过麻烦,我们直接将它抽出来形成一个工具类,执行浅克隆就调用一次,就很方便

新建软件包utils,类名为CopyUtil,里面有两个方法,对象复制和列表复制



import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

public class CopyUtil {

    /**
     * 单体复制
     */
    public static <T> T copy(Object source, Class<T> clazz) {
        if (source == null) {
            return null;
        }
        T obj = null;
        try {
            obj = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        BeanUtils.copyProperties(source, obj);
        return obj;
    }

    /**
     * 列表复制
     */
    public static <T> List<T> copyList(List source, Class<T> clazz) {
        List<T> target = new ArrayList<>();
        if (!CollectionUtils.isEmpty(source)){
            for (Object c: source) {
                T obj = copy(c, clazz);
                target.add(obj);
            }
        }
        return target;
    }
}

修改一下Service层代码,将整个复制过程改为调用工具类

 public List<EbookResp> list(EbookReq req){
        //ebookExample相当于一个查询条件的对象,之前写为null代表*
        EbookExample ebookExample = new EbookExample();
        EbookExample.Criteria criteria = ebookExample.createCriteria();
        //以上为固定方法用于模糊查询
        criteria.andNameLike("%"+req.getName()+"%");

        List<Ebook> ebookList = EbookMapper.selectByExample(ebookExample);
        //我们现在要做的是将list<Ebook>转化成list<EbookResp>,也就是进行集合的复制

    
        List<EbookResp> list=CopyUtil.copyList(ebookList,EbookResp.class);
        return list;
    }

okk,最后运行一遍,结果也没有问题

补充一下,如何传参数就进行模糊查询,不传参数就是查询整个列表,动态的sql查询

只需要加一个if判断我们要查询的这个参数是不是空

if(!ObjectUtils.isEmpty(req.getName())) {
            criteria.andNameLike("%" + req.getName() + "%");
        }

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值