Home

Mybatis Example的高级用法

一. mapper接口中的函数及方法

方法名 功能
int countByExample(UserExample example) 按条件计数
int deleteByPrimaryKey(Integer id) 按主键删除
int deleteByExample(UserExample example) 按条件查询
String/Integer insert(User record) 插入数据(返回值为ID)
User selectByPrimaryKey(Integer id) 按主键查询
ListselectByExample(UserExample example) 按条件查询
ListselectByExampleWithBLOGs(UserExample example) 按条件查询(包括BLOB字段)。只有当数据表中的字段类型有为二进制的才会产生。
int updateByPrimaryKey(User record) 按主键更新
int updateByPrimaryKeySelective(User record) 按主键更新值不为null的字段
int updateByExample(User record, UserExample example) 按条件更新
int updateByExampleSelective(User record, UserExample example) 按条件更新值不为null的字段

二. example实例方法

example 用于添加条件,相当于where后面的部分,理论上单表的任何复杂条件查询都可以使用example来完成。

方法名 功能
example.setOrderByClause(“字段名 ASC”) 添加升序排列条件,DESC为降序
example.setDistinct(false) 去除重复,boolean型,true为选择不重复的记录。
example.and(Criteria criteria) 为example添加criteria查询条件,关系为与
example.or(Criteria criteria) 为example添加criteria查询条件,关系为或  
criteria.andXxxIsNull 添加字段xxx为null的条件  
criteria.andXxxIsNotNull 添加字段xxx不为null的条件  
criteria.andXxxEqualTo(value) 添加xxx字段等于value条件
criteria.andXxxNotEqualTo(value) 添加xxx字段不等于value条件
criteria.andXxxGreaterThan(value) 添加xxx字段大于value条件
criteria.andXxxGreaterThanOrEqualTo(value) 添加xxx字段大于等于value条件
criteria.andXxxLessThan(value) 添加xxx字段小于value条件
criteria.andXxxLessThanOrEqualTo(value) 添加xxx字段小于等于value条件
criteria.andXxxIn(List<?>) 添加xxx字段值在List<?>条件
criteria.andXxxNotIn(List<?>) 添加xxx字段值不在List<?>条件
criteria.andXxxLike(“%”+value+”%”) 添加xxx字段值为value的模糊查询条件
criteria.andXxxNotLike(“%”+value+”%”) 添加xxx字段值不为value的模糊查询条件
criteria.andXxxBetween(value1,value2) 添加xxx字段值在value1和value2之间条件
criteria.andXxxNotBetween(value1,value2) 添加xxx字段值不在value1和value2之间条件

Read more

SpringBoot添加swagger2接口文档并添加全局Authorization参数

依赖包

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.6.1</version>
</dependency>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.6.1</version>
</dependency>

配置类(securitySchemes与securityContexts作用为配置全局Authorization参数)

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    //http://localhost:9007/swagger-ui.html
    @Bean
    public Docket createRestApi() {

        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("cn.com.dinglisec.iot.uaa.api"))
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("springboot利用swagger构建api文档")
                .description("简单优雅的restful风格")
                .termsOfServiceUrl("")
                .version("1.0")
                .build();
    }

    private List<ApiKey> securitySchemes() {
        List<ApiKey> apiKeys = new ArrayList<>();
        apiKeys.add(new ApiKey("Authorization", "Authorization", "header"));
        return apiKeys;
    }

    private List<SecurityContext> securityContexts() {
        List<SecurityContext> securityContexts = new ArrayList<>();
        securityContexts.add(SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex("^(?!auth).*$")).build());
        return securityContexts;
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        List<SecurityReference> securityReferences = new ArrayList<>();
        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
        return securityReferences;
    }

}

配置跳过过滤器 解决swagger2不能获取页面的问题

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private static final PathMatcher pathMatcher = new AntPathMatcher();

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        if (StringUtils.contains(request.getServletPath(), "swagger")
                || StringUtils.contains(request.getServletPath(), "webjars")
                || StringUtils.contains(request.getServletPath(), "v2")) {
            if (request.getServerName().equals("localhost")) {
                filterChain.doFilter(request, response);
            }
        } else {
            if (isExceededUrl(request)) {
                // 登录注册请求直接放行
                filterChain.doFilter(request, response);
            } else {
                // 获取请求头中的Authorization信息
                String tokenHeader = request.getHeader(TokenConstants.TOKEN_HEADER);

                // token不存在则返回
                if (StringUtils.isBlank(tokenHeader) || !tokenHeader.startsWith(TokenConstants.TOKEN_PREFIX)) {
                    ServletOutputStream out = response.getOutputStream();
                    out.print(ResponseConstants.TOKEN_IS_INVALID);
                    out.close();
                    return;
                }

                // token过期返回
                if (JwtUtil.isExpiration(JwtUtil.getTokenByHeader(tokenHeader))) {
                    ServletOutputStream out = response.getOutputStream();
                    out.print(ResponseConstants.TOKEN_IS_INVALID);
                    out.close();
                    return;
                }

                String uid = "";
                try {
                    uid = JwtUtil.getUidByTokenHeader(request.getHeader(TokenConstants.TOKEN_HEADER));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                request.setAttribute("uid", uid);

                HttpServletRequest req = (HttpServletRequest) request;
                MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(req);
                mutableRequest.putHeader("uid", uid);
                filterChain.doFilter(request, response);
            }
        }
    }

    /**
     * @Description:我们只对地址 /api 开头的api检查jwt. 不然的话登录/login也需要jwt 做url匹配,参考
     *                     https://www.cnblogs.com/zhangxiaoguang/p/5855113.html
     * @param request
     * @return boolean
     */
    private boolean isProtectedUrl(HttpServletRequest request) {
        return pathMatcher.match("/**", request.getServletPath());
    }

    /**
     * @Description:登录注册不做校验
     * @param request
     * @return boolean
     */
    private boolean isExceededUrl(HttpServletRequest request) {
        return pathMatcher.match("/user/login", request.getServletPath())
                || pathMatcher.match("/user/register", request.getServletPath());
    }

}

Read more

46. 全排列

  • 难度中等
  • 本题涉及算法深度优先搜索(DFS)
  • 思路深度优先搜索(DFS)
  • 类似题型

题目46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

解题思路

DFS 通用解题步骤

  1. 截止条件
  2. 遍历候选节点
  3. 筛选

DFS搜索执行顺序

如下图

dfs

注意点

  1. res.add(new ArrayList<>(list))res.add(list) 这两个的区别,楼主在这里花了很多时间,读者可以复制在自己的编辑器中看看效果
  2. 当直接发回list 结果为 [] [] [] [] [] [] ,因为是list 只是引用,在遍历的过程中还会继续对list操作
  3. 也就是说,当在返回数据类型为引用类型,需要通过new的方式做返回

参考视频

代码

class Solution {

    List<List<Integer>> res = new ArrayList<List<Integer>>();
    public List<List<Integer>> permute(int[] nums) {
        List<Integer> list = new ArrayList<>();
        boolean[] used = new boolean[nums.length];// 添加判断条件
        DFS(nums,list,used);
        return res;
    }

    public List<Integer> DFS(int[] nums,List<Integer> list,boolean[] used) {
        // 1.截止条件
        if(list.size()==nums.length) {
        //    res.add(list); // 这里是重点
            res.add(new ArrayList<>(list)); // 这里是重点
            return list;
        }

        // 2.遍历候选节点
        for (int i=0;i<nums.length;i++) {
            int c = nums[i];
            // 2.1 筛选
            if (used[i]!=true) {
                list.add(c);
                used[i] = true;
                DFS(nums,list,used);
                list.remove(list.size()-1);
                used[i] = false;
            }
        }
        return list;
    }

}

Read more

69. x 的平方根


题目 69. x 的平方根

实现 int sqrt(int x) 函数。

计算并返回 x 的平方根,其中 x 是非负整数。

由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。

示例

示例 1:

输入: 4
输出: 2

示例 2:

输入: 8
输出: 2
说明: 8 的平方根是 2.82842...,
     由于返回类型是整数,小数部分将被舍去。

解题思路

查找或者搜索型的题目,很自然的会往 二叉树 DFS BFS 等上面套

几个坑点

  1. 对于输入参数的判断,可以先处理
  2. right 不能随便+1,有可能溢出 int 或者 long的长度
  3. 平方需要用的结果需要转long,防止溢出 int

代码

class Solution {
    public int mySqrt(int x) {
        if (x<2)
            return x;
        int left = 0;
        // x 一定大于 x/2
        int right = x/2+1;

        while (left<right) {
            // 这个是需要注意的点,平放有可能会超出int范围
            int mid = left+(right-left)/2;
            long num = (long)mid * mid;
            if (num==x)
                return mid;
            if (num>x)
                right=mid;
            else
                left=mid+1;
        }

        return left-1;
    }
}

Read more

34. 在排序数组中查找元素的第一个和最后一个位置


题目34. 在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

你的算法时间复杂度必须是 O(log n) 级别。

如果数组中不存在目标值,返回 [-1, -1]。

示例

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

解题思路

  • 对于有边界的题,需要考虑左边界和有边界

对于 letf right +-1 的说明 可参考

二分查找细节详解,顺便赋诗一首

代码

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int len = nums.length;
        int[] res = new int[]{-1,-1};
        int left =0;
        int right = len;
        // 先找左边界
        while (left<right){
            int mid = left+(right-left)/2;
            if (nums[mid] == target)
                res[0] = mid;
            if (nums[mid]>=target) {
                right = mid;

            }
            else
                left = mid+1;
        }

        // 先找右边界
        right = len;
        while (left<right){
            int mid = left+(right-left)/2;
            if (nums[mid] == target)
                res[1] = mid;
            if (nums[mid]<=target) {
                left = mid+1;
            }
            else
                right = mid;
        }
        return res;
    }
}

Read more

深度优先搜索(DFS)

解题步骤

DFS 通用解题步骤

  1. 截止条件
  2. 遍历候选节点
  3. 筛选

DFS搜索执行顺序

  • 如下图

dfs

力扣对应题目

面试题 08.07. 无重复字符串的排列组合

通用DFS解题代码

public static String dfs(char[] chars,Stack stack) {
        // 1.截止条件
        if (stack.size()==chars.length) {
            List<String> list = new ArrayList<>();
            System.out.println(stack.toString());
            return stack.toString();
        }

        // 2.遍历候选节点
        for (int i=0;i<chars.length;i++) {
            char c = chars[i];
            // 2.1 筛选
            if (chars[i]!='0') {
                stack.push(c);
                chars[i] = '0';
                dfs(chars,stack);
                stack.pop();
                chars[i] = c;
            }
        }
        return stack.toString();
    }

参考视频

Read more

JPA通过querydsl做连表查询

结论:

  • jpa只适合单表操作
  • 通过 querydsl 实现复杂的sql (在复杂的连表面前也难办)
  • jpa 是个大坑,做链表查询会把人累死
  • 首选 mybitas
  • 有哪个大神能做出来 记得@下
  • 文章末尾有querydsl 相关配置

需要实现sql

select me.address as address, me.totalChecked as totalChecked, me.avatar as avatar, info.checked as checked, info.checkedTime as checkedTime, info.upvoteNumber as upvoteNumber, info.username as username
from (select member1.address, member1.totalChecked, member1.avatar, member1.username
from Member member1
where member1.status = 0) as me
left join (
select checkDayInfo.username, checkDayInfo.checked, checkDayInfo.checkedTime, checkDayInfo.upvoteNumber
from CheckDayInfo checkDayInfo
where checkDayInfo.date = '2020-04-17'
) as info
on me.username = info.username
order by info.checked desc, info.checkedTime asc

相关代码

import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.QueryModifiers;
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.*;
import com.querydsl.core.types.dsl.*;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.jpa.sql.JPASQLQuery;
import com.querydsl.sql.DerbyTemplates;
import com.querydsl.sql.SQLExpressions;
import com.querydsl.sql.SQLTemplates;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.stream.Collectors;


public class PageTest extends SpringbootJpaApplicationTests {

    @Autowired
    private EntityManager entityManager;

    //查询工厂实体
    private JPAQueryFactory queryFactory;


    //实例化控制器完成后执行该方法实例化JPAQueryFactory
    @PostConstruct
    public void initFactory() {
        queryFactory = new JPAQueryFactory(entityManager);
    }


    /**
     * 普通查询
     */
    @Test
    public void getcheckDayInfo() {
        QCheckDayInfo qCheckDayInfo = QCheckDayInfo.checkDayInfo;
        List<CheckDayInfo> checkDayInfo = queryFactory
                .selectFrom(qCheckDayInfo)
                .where(
                        qCheckDayInfo.username.eq("javaniuniu"),
                        qCheckDayInfo.checked.eq(1)
                )
                .fetch();
        System.out.println(checkDayInfo);
    }

    /**
     * BooleanBuilder 绑定条件进行查询
     */
    @Test
    public void getCheckDayInfos() {
        // 使用 QueryDSL 进行查询
        QCheckDayInfo qCheckDayInfo = QCheckDayInfo.checkDayInfo;
        // 定于获取条件
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        // 放入要查询的条件信息
        booleanBuilder.and(qCheckDayInfo.username.contains("javaniuniu"));
        // queryFactory 是上方定义的工厂实体
        // select(生成的实体类的字段).from(生成实体类的名称).where(上方要查询的条件).orderBy(排序).fetch()进行查询
        List<CheckDayInfo> checkDayInfoList = queryFactory.select(qCheckDayInfo)
                .from(qCheckDayInfo)
                .where(booleanBuilder)
                .orderBy(qCheckDayInfo.date.asc())
                .fetch();
        System.out.println(checkDayInfoList);
    }

    /**
     * 分页查询
     */
    @Test
    public void getCheckDayInfoPage() {
        Pageable pageable = PageRequest.of(0, 5);
        QCheckDayInfo qCheckDayInfo = QCheckDayInfo.checkDayInfo;
        QueryResults<CheckDayInfo> checkDayInfo = queryFactory
                .selectFrom(qCheckDayInfo)
                .orderBy(qCheckDayInfo.checked.desc())
                .orderBy(qCheckDayInfo.checkedTime.desc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetchResults();
        System.out.println(checkDayInfo);
    }

    /**
     * 通过 JPASQLQuery 做分页查询
     */
    @Test
    public void getbCheckDayInfoPageByJPASQLQuery() {
        SQLTemplates templates = new DerbyTemplates();

        JPASQLQuery<?> jpasqlQuery = new JPASQLQuery<Void>(entityManager, templates);
        Pageable pageable = PageRequest.of(0, 5);
        QCheckDayInfo qCheckDayInfo = QCheckDayInfo.checkDayInfo;
        QueryResults<CheckDayInfo> checkDayInfo = jpasqlQuery
                .select(qCheckDayInfo)
                .from(qCheckDayInfo)
                .orderBy(qCheckDayInfo.checked.desc())
                .orderBy(qCheckDayInfo.checkedTime.desc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetchResults();
        System.out.println(checkDayInfo);
    }

    /**
     * 返回数据到DTO
     */
    @Test
    public void getCheckDayInfoDTO() {
        QCheckDayInfo qCheckDayInfo = QCheckDayInfo.checkDayInfo;
        Pageable pageable = PageRequest.of(0, 2);
        List<CheckDayInfoDTO> checkDayInfo = queryFactory
                .select(
                        qCheckDayInfo.username,
                        qCheckDayInfo.checked,
                        qCheckDayInfo.checkedTime,
                        qCheckDayInfo.upvoteNumber
                )
                .from(qCheckDayInfo)
//                .where(
//                        qCheckDayInfo.checked.eq(1)
//                )
                .orderBy(qCheckDayInfo.checked.desc())
                .orderBy(qCheckDayInfo.checkedTime.asc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch()
                .stream()
                .map(tuple -> CheckDayInfoDTO.builder()
                        .username(tuple.get(qCheckDayInfo.username))
                        .checked(tuple.get(qCheckDayInfo.checked))
                        .checkedTime(tuple.get(qCheckDayInfo.checkedTime))
                        .upvoteNumber(tuple.get(qCheckDayInfo.upvoteNumber))
                        .build()
                )
                .collect(Collectors.toList());
        System.out.println(checkDayInfo);
    }


    /**
     * 通过 JPAQuery 做连表查询
     * 但是不能分页
     */
    @Test
    public void getCheckDayInfoDTOPages() {

        SQLTemplates templates = new DerbyTemplates();

        JPASQLQuery<?> jpasqlQuery = new JPASQLQuery<Void>(entityManager, templates);

        JPAQuery jpaQuery = new JPAQuery(entityManager);
        Pageable pageable = PageRequest.of(1, 2);

        String date = "2020-04-17";
        QMember qMember = QMember.member;
        QCheckDayInfo qCheckDayInfo = QCheckDayInfo.checkDayInfo;

        StringPath me = Expressions.stringPath("me");
        StringPath info = Expressions.stringPath("info");


        SimpleTemplate<String> address = Expressions.template(String.class, "me.address");
        NumberTemplate<Integer> totalChecked = Expressions.numberTemplate(Integer.class, "me.totalChecked");
        SimpleTemplate<String> avatar = Expressions.template(String.class, "me.avatar");
        SimpleTemplate<String> me_username = Expressions.template(String.class, "me.username");

        NumberTemplate<Integer> checked = Expressions.numberTemplate(Integer.class, "info.checked");
        SimpleTemplate<String> checkedTime = Expressions.template(String.class, "info.checkedTime");
        NumberTemplate<Integer> upvoteNumber = Expressions.numberTemplate(Integer.class, "info.upvoteNumber");
        SimpleTemplate<String> username = Expressions.template(String.class, "info.username");

        OrderSpecifier orderByChecked = new OrderSpecifier(Order.DESC,
                Expressions.template(String.class, "info.checked"));

        OrderSpecifier orderByCheckedTime = new OrderSpecifier(Order.ASC,
                Expressions.template(String.class, "info.checkedTime"));

//        long l1 = 2;
//        long l2 = 1;
//
//        QueryModifiers queryModifiers = new QueryModifiers(l1, l2);

        SubQueryExpression queryCheckByDate = SQLExpressions
                .select(
                        qCheckDayInfo.username,
                        qCheckDayInfo.checked,
                        qCheckDayInfo.checkedTime,
                        qCheckDayInfo.upvoteNumber
                )
                .from(qCheckDayInfo)
                .where(qCheckDayInfo.date.eq(date));

        SubQueryExpression queryMember = SQLExpressions
                .select(
                        qMember.address,
                        qMember.totalChecked,
                        qMember.avatar,
                        qMember.username
                )
                .from(qMember)
                .where(qMember.status.eq(0));

        QueryResults<CheckDayInfoDTO> checkDayInfoDTOS = jpasqlQuery.select(
                Projections.bean(
                        CheckDayInfoDTO.class,
                        address.as("address"), totalChecked.as("totalChecked"), avatar.as("avatar"), checked.as("checked"),
                        checkedTime.as("checkedTime"),
                        upvoteNumber.as("upvoteNumber"), username.as("username")))
                .from(qMember)
                .leftJoin(queryCheckByDate, info).on(me_username.eq(username))
                .orderBy(orderByChecked)
                .orderBy(orderByCheckedTime)
//                .limit(pageable.getPageSize()) // 做不了分页
//                .offset(pageable.getOffset())
//                .restrict(queryModifiers)
                .fetchResults();
        System.out.println(checkDayInfoDTOS);


    }

}

querydsl 相关配置

<!-- QueryDSL 相关依赖 -->
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
            <version>4.1.4</version>
        </dependency>
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>4.3.1</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.querydsl/querydsl-sql -->
        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-sql</artifactId>
            <version>4.3.1</version>
        </dependency>
<!--         https://mvnrepository.com/artifact/com.mysema.querydsl/querydsl-jdo-->
        <dependency>
            <groupId>com.mysema.querydsl</groupId>
            <artifactId>querydsl-jdo</artifactId>
            <version>3.7.4</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.mysema.querydsl/querydsl-apt -->
        <dependency>
            <groupId>com.mysema.querydsl</groupId>
            <artifactId>querydsl-sql</artifactId>
            <version>3.7.4</version>
            <scope>provided</scope>
        </dependency>


        ...

        <!--因为是类型安全的,所以还需要加上Maven APT plugin,使用 APT 自动生成一些类:-->
            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.1.3</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources</outputDirectory>
                            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

生成 Q实体类

pic

参考文档

Read more