技术点积累

Posted luboyan2524

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了技术点积累相关的知识,希望对你有一定的参考价值。

1. 通用分页条展示思路分析

1. 构建分页条数据:页码列表,分页条的本质就是在页面显示页码列表
  • 已知当前页pageNum和总页数totalPages,根据每页要求显示的页码列表的条数,得出页码列表的头startPage和尾endPage,在页面循环列表,即可展示出分页条。

  • 分页列表头和尾的确定:假设页面要求显示10个页码,那么可以选择以当前页前4后5的显示方式,确定显示方式后,便可以计算头尾以构建分页列表。

  Integer startPage = pageNum - 4;
Integer endPage = pageNum + 5;
if (startPage < 1){ //判断列表头startPage是否 < 1
   startPage = 1;
   endPage = startPage + 9;
}
if (endPage > totalPage){ //判断列表尾endPage是否 > totalPages
   endPage = totalPage;
   startPage = endPage - 9;
}
  • 在页面获取以startPage为头endPage为尾的列表,并循环展示分页条

2. 前后端数据交互
  • 前端请求参数:pageNo、pageSize、QueryParams

  • 后端响应数据:

    • html异步请求:

      PageBean<T> {pageNo,pageSize,totalCount,totalPage,List<T> result,QueryParams}

      可以在js中定义startPage和endPage

    • 模板页同步请求:

      PageBean<T> {pageNo,pageSize,totalCount,totalPage,List<T> result,QueryParams,startPage,endPage}

3. 页码选中状态显示

是否选中状态的通用思路:定义一个变量n记录选中状态的状态值,然后把当前变量与n比较,如果当前变量等于n记录的选中状态值,那么当前变量即选中状态

  • 这里循环页码列表获取的变量page和当前页pageNum(记录选中状态的变量n)比较,如果page==pageNum,那么page对应的页码列表中页码即开启选中状态

  
<li th:class="${page==pageNo?‘active‘:‘‘}" th:each="page:${#numbers.sequence(startPage,endPage)}">
   <a th:href="${#strings.replace(url,‘&pageNo=‘+pageNo,‘&pageNo=‘+page)}" th:text="${page}"></a>
</li>
 
  • 引入分页助手

  
<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper</artifactId>
   <version>3.7.5</version>
</dependency>
  • 增强

  
@Override
public PageResult<Brand> findPage(Integer page, Integer size) {
   //PageHelper.startPage设置分页,增强方法体
   PageHelper.startPage(page,size);
   //Page<T>接收查询结果,增强返回值
   Page<Brand> pageResult = (Page<Brand>) brandMapper.selectAll();
   return new PageResult<>(pageResult.getTotal(), pageResult.getResult());
}

 

2. 服务端页面渲染技术Thymeleaf

  • thymeleaf与vue.js不同之处在于thymeleaf是在服务端渲染完成后,再将静态页面发给前台,相比前端vue.js发送异步请求获取数据后,再在前台进行渲染的情况, thymeleaf不会出现页面内容延迟加载的状况;

  • thymeleaf与jsp一样, 都是服务端渲染页面, 但thymeleaf相比jsp具有更强大的功能, 同时thymeleaf也是springboot官方推荐的渲染引擎, thymeleaf可以类比为更高级的jsp

1. 生成静态页面:
  • 添加thymeleaf依赖

  
<dependencies>
   <dependency>
       <groupId>org.thymeleaf</groupId>
       <artifactId>thymeleaf</artifactId>
       <version>3.0.11.RELEASE</version>
   </dependency>
</dependencies>
  • 在applicationContext-thymeleaf.xml中配置模版引擎、视图解析器、模版解析器

  
<!-- 配置模板引擎 -->
<bean id="templateEngine"
     class="org.thymeleaf.spring5.SpringTemplateEngine">
   <property name="templateResolver" ref="templateResolver"/>
</bean>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
   <property name="templateEngine" ref="templateEngine"/>
   <property name="characterEncoding" value="UTF-8"/>
</bean>
<!-- 配置模板解析器 -->
<bean id="templateResolver"
     class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
   <property name="prefix" value="/WEB-INF/templates/"/>
   <property name="suffix" value=".html"/>
   <property name="characterEncoding" value="UTF-8"/>
   <property name="templateMode" value="HTML"/>
</bean>
  • 在webapp/WEB-INF目录下创建模板资源test.html

  • 创建上下文对象Context, 用于向模版传递数据模型Map

  
//1. 创建上下文对象,传递数据模型
Context context = new Context();
Map<String,Object> dataModel = new HashMap<>();
//查询页面渲染需要的数据(主要业务逻辑,此处略...)
dataModel.put("name",object);
context.setVariables(dataModel);
  • 创建目标文件输出流对象PrintWriter,调用模板引擎的process方法向生成静态页面目标文件

  
@Value("${pagePath}")
private String pagePath;
try {
   //2. 创建目标文件输出流对象
   File dir = new File(pagePath);
   if (!dir.exists()){
       dir.mkdirs();
  }            
   File dest = new File(pagePath + sku.getId() + ".html");
   PrintWriter pw = new PrintWriter(dest, "UTF-8");
   //3. 生成目标静态页面文件
   templateEngine.process("item",context,pw);
} catch (FileNotFoundException e) {
   e.printStackTrace();
} catch (UnsupportedEncodingException e) {
   e.printStackTrace();
}
2. 直接动态渲染
  
@Controller//这里直接转发至服务端模板页面渲染,而不是返回数据给前端,所以不需要用RestController
public class IndexController {
   @RequestMapping("/index")
   public String index(Model model){
       //注意和生成静态页面区别,这里是直接return模版页面渲染,而不是通过流生成静态页面
       return "index";
  }
}
3. 常用页面标签
标签说明示例
th:text 指定文本内容 <p th:text="${collect.description}"></p>
th:utext 支持html内容渲染 <p th:utext="${htmlcontent}"></p>
th:each 1. 循环列表,userStat为循环状态量, 有index/count/current/even/odd/first/last等属性;2. 循环map集合,param.key、param.value分别获取map的键值 <tr th:each="user:${users}"></tr>或者<tr th:each="param : ${params}" th:text = "${param.key + ‘:‘ + param.value}"></tr>
th:if 判断是否显示当前标签 <a th:if="${userId == collect.userId}" >
th:href 链接地址 <a th:href="${url}"/>
th:src 图片类地址引入 <img th:src="${user.image}" />
th:inline 定义js脚本可以使用渲染变量数据,使用方法:url = url.replace("&pageNo="+/星号[[${pageNo}]]星号/, "&pageTo="+pageTo) <script th:inline="javascript">
numbers.formatDecimal 保留两位小数 ${#numbers.formatDecimal(arg,0,2) }
numbers.sequence 以startPage、endPage为头尾生成列表,默认步长值为1 ${#numbers.sequence(startPage,endPage)}
strings.replace 替换字符串 ${#strings.replace(url,‘abc‘,‘cba‘)}
strings.startWith 判断字符串是否以某子串开头(boolean) ${#strings.startsWith(url,‘http‘)}
strings.substring 截取字符串子串,指定开始索引 ${#strings.substring(url,5)
maps.containsKey 判断Map集合是否包含某个key ${#maps.containsKey(searchMap,‘category‘)}

 


 

3. SpringDataRedis——RedisTemplate

1. 引入依赖
  
<!-- 连接redis服务器 -->
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.9.0</version>
</dependency>
<!-- 引入spring-data-redis -->
<dependency>
   <groupId>org.springframework.data</groupId>
   <artifactId>spring-data-redis</artifactId>
   <version>2.0.5.RELEASE</version>
</dependency>
2. 配置spring提供的RedisTemplate

SpringDataRedis底层封装了jedis,所以先配置JedisConnectionFactory,再注入到RedisTemplate中

  
<!-- Jedis连接配置对象JedisPoolConfig -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">  
   <property name="maxIdle" value="${redis.maxIdle}" />  
   <property name="maxWaitMillis" value="${redis.maxWait}" />  
</bean>  
<!-- Jedis连接工厂JedisConnectionFactory -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
     p:host-name="${redis.host}" p:port="${redis.port}" p:password="${redis.pass}" p:pool-config-ref="poolConfig"/>  
<!-- spring提供的模板工具redisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">  
   <property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>
3. 在代码中注入RedisTemplate对象,绑定大Key,操作redis
  • 对象操作:boundValueOps

  
public void setValue(){
   redisTemplate.boundValueOps("name").set("青橙电商");
}
public void getValue(){
   String name = (String) redisTemplate.boundValueOps("name").get();
   System.out.println(name);
}
public void deleValue(){
   redisTemplate.delete("name");
}
  • Set集合操作:boundSetOps

  public void setValue(){
   redisTemplate.boundSetOps("nameSet").add("曹操");
   redisTemplate.boundSetOps("nameSet").add("刘备");
   redisTemplate.boundSetOps("nameSet").add("孙权");
}
public void getValue(){
   Set nameSet = redisTemplate.boundSetOps("nameSet").members();
   System.out.println(nameSet);
}
public void deleValue(){
   redisTemplate.boundSetOps("nameSet").remove("曹操");
   System.out.println(redisTemplate.boundSetOps("nameSet").members());
?
   redisTemplate.delete("nameSet");
}

 

  • Map集合操作:boundHashOps

  
public void setValue(){
   redisTemplate.boundHashOps("nameHash").put("0","唐僧");
   Map<String,String> map = new HashMap();
   map.put("1","悟空");
   map.put("2","八戒");
   map.put("3","沙僧");
   redisTemplate.boundHashOps("nameHash").putAll(map);
}
public void getValue(){
   String name = (String) redisTemplate.boundHashOps("nameHash").get("1");
   System.out.println(name);
}
public void deleValue(){
   redisTemplate.boundHashOps("nameHash").delete("2");
   System.out.println(redisTemplate.boundHashOps("nameHash").values());
}
  • 有序队列操作(存取顺序):boundListOps

  
public void setValue(){
   redisTemplate.boundListOps("nameList").rightPush("中间值");
   redisTemplate.boundListOps("nameList").rightPush("右压栈");
   redisTemplate.boundListOps("nameList").leftPush("左压栈");
   redisTemplate.boundListOps("nameList").rightPush("测试删除的索引位置");
   redisTemplate.boundListOps("nameList").rightPush("测试删除");
   redisTemplate.boundListOps("nameList").rightPush("测试删除");
}
public void getValue(){
   List nameList = redisTemplate.boundListOps("nameList").range(0, -1);
   System.out.println(nameList);
   //按索引取值
   String valueOfIndex = (String) redisTemplate.boundListOps("nameList").index(1);
   System.out.println(valueOfIndex);
}
public void deleValue(){
   //remove(删除的元素个数, 删除的元素值); 按索引从小到大查询指定个数的元素并删除
   redisTemplate.boundListOps("nameList").remove(2,"测试删除");
   System.out.println(redisTemplate.boundListOps("nameList").range(0,-1));
}
  • 有序队列操作(需要经常发生顺序变动的情况):boundZSetOps

  
public void setValue(){
   redisTemplate.boundZSetOps("nameZset").add("曹操",10000);
   redisTemplate.boundZSetOps("nameZset").add("刘备",1000);
   redisTemplate.boundZSetOps("nameZset").add("孙权",10);
}
public void getValue(){
   //分数由低到高排序(默认)
   Set<String> nameZset1 = redisTemplate.boundZSetOps("nameZset").range(0, -1);
   System.out.println(nameZset1);
   //分数由高到低排序(逆向)
   Set<String> nameZset2 = redisTemplate.boundZSetOps("nameZset").reverseRange(0, -1);
   System.out.println(nameZset2);
   //带分数取值
   Set<ZSetOperations.TypedTuple> nameTupleSet = redisTemplate.boundZSetOps("nameZset").rangeWithScores(0, -1);
   for (ZSetOperations.TypedTuple nameTuple : nameTupleSet) {
       System.out.println(nameTuple.getValue()+"..."+nameTuple.getScore());
  }
}
public void incrementScore(){
   redisTemplate.boundZSetOps("nameZset").incrementScore("孙权",1190);
   System.out.println(redisTemplate.boundZSetOps("nameZset").range(0,-1));
}
public void deleValue(){
   redisTemplate.boundZSetOps("nameZset").remove("孙权");
   System.out.println(redisTemplate.boundZSetOps("nameZset").range(0,-1));
}
  • 通用操作:

    1. redisTemplate. delete(redisKey); 删除redisKey-value的方法 ; . redisTemplate. boundXxxOps(). expire(long , TimeUnit); 指定大Key的存活时间(短信验证码)

    2. 取不到对象, 返回null; 取不到集合, 返回[ ]


 

4. Java 8 日期、时间API(java.time.*)

LocalDate不可用作前端传参,可以用String接收日期对象,再用LocalDate转换

1. 常用时间类
  • LocalDate:表示默认格式yyyy-MM-dd的日期对象

    LocalDate today = LocalDate.now():获取当前日期对象

    LocalDate firstDayOf2019 = LocalDate.of(2019, Month.JANUARY, 1):获取指定日期对象

  • LocalTime:表示默认格式hh:mm:ss.zzz的时间对象

    LocalTime time = LocalTime.now():获取当前时间对象

    LocalTime specTime = LocalTime.of(23,23,23,23):获取指定时间对象23:23:23.023

  • LocalDateTime:表示日期+时间对象

    LocalDateTime time = LocalDateTime.now():获取当前日期时间对象

    LocalDateTime firstDayOf2019 = LocalDate.of(2019, Month.JANUARY, 1,0,0,0,0):获取指定日期时间对象

2. 日期时间API工具
API说明
LocalDate#isBefore(LocalDate date) 判断是否在指定日期之前
LocalDate#plusDays/plusWeeks/plusMonths/minus.. 从当前日期加减日、周、月后得到日期
Period period LocalDate#until(LocalDate date) 获取到指定日期之间的天数
LocalDate#format(DateTimeFormatter.ofPattern("dd-MM-yyyy")) 按指定格式格式化日期对象
LocalDate.parse("yyyy-MM-dd") 解析日期字符串

 

5. 阿里大于短信微服务

1. 添加依赖
  
<dependency>
   <groupId>com.aliyun</groupId>
   <artifactId>aliyun-java-sdk-core</artifactId>
   <version>4.0.3</version>
</dependency>
2. 配置文件
  
accessKeyId=LTAIfWgh9uJxqyJM
accessSecret=NMzCzy7mGry292XYlaTRxVmRVOsDL7
#短信模版号
smsCode=SMS_173341860
#生成的验证码
param={"code":"[value]"}
3. 短信工具类SmsUtil
  
public class SmsUtil {
   @Value("${accessKeyId}")
   private String accessKeyId;
   @Value("${accessSecret}")
   private String accessSecret;
   public CommonResponse sendSms(String phone, String smsCode, String param){
       DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessSecret);
       IAcsClient client = new DefaultAcsClient(profile);
       CommonRequest request = new CommonRequest();
       request.setMethod(MethodType.POST);
       request.setDomain("dysmsapi.aliyuncs.com");
       request.setVersion("2017-05-25");
       request.setAction("SendSms");
       request.putQueryParameter("RegionId", "cn-hangzhou");
       request.putQueryParameter("SignName", "青橙");
       request.putQueryParameter("PhoneNumbers",phone);
       request.putQueryParameter("TemplateCode", smsCode);
       request.putQueryParameter("TemplateParam", param);
       try {
           CommonResponse response = client.getCommonResponse(request);
           return response;
      } catch (Exception e) {
           e.printStackTrace();
           return null;
      }
  }
}

 

6. Spring-Security安全框架入门(认证)

1. 引入spring-security依赖
  
<dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-web</artifactId>
   <version>${spring.version}</version>
</dependency>
<dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-config</artifactId>
   <version>${spring.version}</version>
</dependency>
2. 创建spring-security.xml配置文件
  
<!--基本配置:
1. 非目标资源解除拦截规则、目标资源拦截规则(<http>)
   2. 认证管理器:自定义认证信息提供者(UserDetailsService);密码加密策略(BCrypt)-->
?
<!-- 1. 配置页面的拦截规则 -->
<!-- 1.1 解除非目标资源的拦截规则 -->
<http pattern="/login.html" security="none"></http>
<http pattern="/login_error.html" security="none"></http>
   <!-- 1.2 配置目标资源(所有资源)必须拥有ROLE_ADMIN的角色才能访问 -->
<http>
   <intercept-url pattern="/**" access="hasRole(‘ROLE_ADMIN‘)"/>
   <!-- 指定登陆页面/目标访问页面/认证失败页面, 所有的页面必须使用绝对路径配置 -->
   <form-login login-page="/login.html" default-target-url="/index.html" authentication-failure-forward-url="/login_error.html" />
   <!-- 退出登录 -->
   <logout />
   <!-- 关闭csrf验证: 跨站请求伪造,csrf会随机产生一个token放到security提供的默认表单中,因为静态页无法动态生成token,所以将此功能关闭。一般静态页采用图形验证码的方式实现防止跨域请求伪造的功能。 -->
   <csrf disabled="true"/>
</http>
?
<!-- 2. 配置认证管理器,获取来自数据库的认证信息 -->
<authentication-manager>
   <authentication-provider user-service-ref="userDetailsService">
       <password-encoder ref="bcryptEncoder"></password-encoder>
   </authentication-provider>
</authentication-manager>
<!-- 2.1 配置自定义认证信息提供者UserDetailsService -->
<beans:bean id="userDetailsService" class="com.qingcheng.demo.UserDetailsServiceImpl"></beans:bean>
<!-- 2.2 加密策略:指定由spring-security提供的相应的解密类 -->
<beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>
</beans:beans>
3. 创建自定义认证信息提供者UserDetailsService
  
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
?
import java.util.ArrayList;
import java.util.List;
?
/** UserDetailsService是spring-security提供的用于从数据库获取用户认证信息,并用UserDatils接口把"认证信息"传给认证管理器的工具接口
*/
public class UserDetailsServiceImpl implements UserDetailsService {
   public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
       List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
       grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
?
       //参数三为用户所具有的认证角色集合
       return new User(username,"$2a$10$amAQ3ClrcXV5K9gg6fsbfuUtdgliLTGvfzZuN3toBDAkbSK1nQliC",
                       grantedAuthorities);
  }
}

 

7. 集合流式操作Stream

1. 生成Stream流的方式
  • Collection体系集合

    使用默认方法stream()生成流, default Stream<E> stream()

  • Map体系集合

    把Map转成Set集合,间接的生成流

  • 数组

    通过Stream静态方法 Stream.of(T... values) 生成流

  
public class StreamDemo {
   public static void main(String[] args) {
       //Collection体系的集合可以使用默认方法stream()生成流
       List<String> list = new ArrayList<String>();
       Stream<String> listStream = list.stream();
       Set<String> set = new HashSet<String>();
       Stream<String> setStream = set.stream();
?
       //Map体系的集合间接的生成流
       Map<String,Integer> map = new HashMap<String, Integer>();
       Stream<String> keyStream = map.keySet().stream();
       Stream<Integer> valueStream = map.values().stream();
       Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
?
       //数组可以通过Stream接口的静态方法of(T... values)生成流
       String[] strArray = {"hello","world","java"};
       Stream<String> strArrayStream = Stream.of(strArray);
       Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
       Stream<Integer> intStream = Stream.of(10, 20, 30);
  }
}
2. Stream的常见操作方法
方法名说明
Stream<T> filter(Predicate predicate) 用于对流中的数据进行过滤
Stream<T> limit(long maxSize) 返回此流中的元素组成的流,截取前指定参数个数的数据
Stream<T> skip(long n) 跳过指定参数个数的数据,返回由该流的剩余元素组成的流
static <T> Stream<T> concat(Stream a, Stream b) 合并a和b两个流为一个流
Stream<T> distinct() 返回由该流的不同元素(根据Object.equals(Object) )组成的流
Stream<T> sorted() 返回由此流的元素组成的流,根据自然顺序排序
Stream<T> sorted(Comparator comparator) 返回由该流的元素组成的流,根据提供的Comparator进行排序
<R> Stream<R> map(Function mapper) 返回由给定函数应用于此流的元素的结果组成的流
IntStream mapToInt(ToIntFunction mapper) 返回一个IntStream其中包含将给定函数应用于此流的元素的结果
void forEach(Consumer action) 对此流的每个元素执行操作
List collect(Collectors. toList()) 把元素收集到List集合中
Set collect(Collectors. toSet()) 把元素收集到Set集合中
Map collect(Collectors. toMap(Function keyMapper,Function valueMapper)) 把元素收集到Map集合中:(keyMapper,valueMapper)分别表示从流中元素获取key和value的方法
  • filter、skip、limit、forEach、collect

  
public class StreamDemo01 {
   public static void main(String[] args) {
       ArrayList<String> list = new ArrayList<String>();
       list.add("林青霞");
       list.add("张曼玉");
       list.add("王祖贤");
       list.add("柳岩");
       list.add("张敏");
       list.add("张无忌");
       //需求1:把list集合中以张开头的,长度为3的元素在控制台输出
       list.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);
       //需求2:跳过2个元素,把剩下的元素中前2个取出存入集合中
       List newList = list.stream().skip(2).limit(2).collect(Collectors.toList);
  }
}
  • map、mapToInt —— IntStream. min() max() sum();

  
public class StreamDemo05 {
   public static void main(String[] args) {
       ArrayList<String> list = new ArrayList<String>();
       list.add("10");
       list.add("20");
       list.add("30");
       list.add("40");
       list.add("50");
       
       //int sum() 返回此流中元素的总和
       int result = list.stream().mapToInt(Integer::parseInt).sum();
       System.out.println(result);
  }
}

 

8. SpringDataMongodb

8.1 Mongodb

Mongodb存储的数据是JSON格式的,相比较redis而言可以存储大的文件数据。一方面mongodb可以灵活存储json,另一方面存储的数据相比于数据库的核心数据不太重要,且没有事务管理要求。

? 1. model

  
@Document(collection = "cms_page")//collection相当于mysql中的表的概念
public class CmsPage {
   @Id
   private String pageId;
   private String siteId;
   //....
}

? 2. dao

  
public interface CmsPageRepository extends MongoRepository<CmsPage,String> {
}

? 3. 基本方法

  
//1. 查询所有
List<CmsPage> all = cmsPageRepository.findAll();
?
//2. 分页查询
int page = 0; //页码从0开始
int size = 10;
Pageable pageable = PageRequest.of(page,size);
Page<CmsPage> all = cmsPageRepository.findAll(pageable);
List<CmsPage> cmsPageList = all.getContent(); //获取数据
long total = all.getTotalElements(); //获取记录数
?
//3. 条件查询
   //创建条件值对象
   CmsPage cmsPage = new CmsPage();
   //设置条件值
   cmsPage.setSiteId("5a751fab6abb5044e0d19ea1");
   cmsPage.setTemplateId("5a962b52b00ffc514038faf7");
   cmsPage.setPageAliase("导航");
//ExampleMatcher.GenericPropertyMatchers.contains() 包含关键字"导航"匹配
//ExampleMatcher.GenericPropertyMatchers.startsWith() 前缀匹配
   ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains()); // 设置pageAliase字段模糊匹配
   //创建条件实例
   Example<CmsPage> example = Example.of(cmsPage,exampleMatcher);
   Page<CmsPage> all = cmsPageRepository.findAll(example, pagebale);
?
//4. 添加
CmsPage cmsPage = cmsPageRepository.save(cmsPage);
?
//根据id查询
Optional<CmsPage> optional = cmsPageRepository.findById(id);
if (optional.isPresent()){
   CmsPage cmsPage = optional.get();
   return cmsPage;
}
return null;
8.2 GridFS

GridFS是Mongodb提供的用于持久化存储文件的模块。它的工作原理是将文件按256kb的大小分割进行存储,GridFS用两个collection存储文件,一个是chunks,用于存储文件的二进制数据,一个是files,用于存储文件的元数据(文件名称、块大小、上传时间等)

  
1. GridFS存储文件
  
@Autowired
private GridFsTemplate gridFsTemplate;
?
public void testStoreBannerFtl() throws FileNotFoundException {
   //创建文件输入流对象
   File file = new File("E:\IdeaProjects\xcEduService\test-freemarker\src\main\resources\templates\index_banner.ftl");
   FileInputStream fileInputStream = new FileInputStream(file);
   //用GridFSTemplate存储文件,返回存储文件的ObjectId
   ObjectId objectId = gridFsTemplate.store(fileInputStream, "轮播图模板测试用");
   System.out.println(objectId);
}
  1. GridFS获取文件

  
@Autowired
private GridFsTemplate gridFsTemplate;
@Autowired
private GridFSBucket gridFSBucket;
?
public void testQueryBannerFtl() throws IOException {
   String fileId = "5d83aaa0f06eb11714b0cd5a";
   //用GridFsTemplate根据id查询文件对象
   GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
   //用gridFSBucket打开下载流对象
   GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
   //创建gridFsResource,用于获取流对象
   GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
   //获取流中的数据
   String content = IOUtils.toString(gridFsResource.getInputStream(),"UTF-8");
   System.out.println(content);
}

 


 

9. Swagger接口测试

? OpenAPI规范(OpenAPI Specification 简称OAS)是Linux基金会的一个项目,试图通过定义一种用来描述API格式或API定义的语言,来规范RESTful服务开发过程

? Swagger是全球最大的OpenAPI规范(OAS)API开发工具框架,支持从设计和文档到测试和部署的整个API生命周期的开发。Spring Boot 可以集成Swagger,生成Swagger接口。

1. Swagger常用注解
注解说明
@Api 修饰整个类,描述Controller的作用
@ApiOperation 描述一个类的一个方法,或者说一个接口
@ApiParam 单个参数描述
@ApiModel 用对象来接收参数
@ApiModelProperty 用对象接收参数时,描述对象的一个字段
@ApiResponse HTTP响应其中1个描述
@ApiResponses HTTP响应整体描述
@ApiError 发生错误返回的信息
@ApiImplicitParam 一个请求参数
@ApiImplicitParams 多个请求参数
  • @ApiImplicitParam的属性:

属性取值作用
paramType   查询参数类型
  path 以地址的形式提交数据
  query 直接跟参数完成自动映射赋值(地址栏拼接查询条件,用对象属性封装)
  body 以流的形式提交 仅支持POST(JSON串提交,用@Requestbody接收)
  header 参数在request headers 里边提交
  form 以form表单的形式提交 仅支持POST
dataType   参数的数据类型 只作为标志说明,并没有实际验证
  Long  
  String  
name   接收参数名
value   接收参数的意义描述
required   参数是否必填
  true 必填
  false 非必填
defaultValue   默认值
2. 测试

在xc-service-api工程下创建config.Swagger2Configuration类,启动项目,访问localhost:31001/swagger-ui.html即可开启测试

  
@Configuration
@EnableSwagger2
public class Swagger2Configuration {
   @Bean
   public Docket createRestApi() {
       return new Docket(DocumentationType.SWAGGER_2)
              .apiInfo(apiInfo())
              .select()
              .apis(RequestHandlerSelectors.basePackage("com.xuecheng"))
              .paths(PathSelectors.any())
              .build();
  }
   private ApiInfo apiInfo() {
       return new ApiInfoBuilder()
              .title("学成网api文档")
              .description("学成网api文档")
//               .termsOfServiceUrl("/")
              .version("1.0")
              .build();
  }
}

 

10. Google guava

 

 

以上是关于技术点积累的主要内容,如果未能解决你的问题,请参考以下文章

技术点积累

QT 实用代码片段

每日随笔2023年02月17日随笔 ( 随便写点 | 技术无关没事别点进来看好好学你的技术 | 低成本创业 | 中产陷阱 | 创业建议 | 积累经营经验 | 工匠型创业 )

javaio流面试题,积累总结

来自菜鸡Java工程师的日积月累

来自菜鸡Java工程师的日积月累