本文共 39406 字,大约阅读时间需要 131 分钟。
文章目录
前言
这是学习springBoot初期的学习笔记。。。欢迎各位大佬指正!!!springBoot中实现单元测试
关于这个单元测试需要了解的知识:
第一点:
junit版本在pom.xml中分为4和5版本,如下:这个是在springBoot的junit4版本
org.junit.vintage junit-vintage-engine RELEASE test
这个是在springBoot的junit5版本
org.junit.jupiter junit-jupiter-engine RELEASE test
也就是j开头的就是5版本,v开头的就是4版本;
第二点:
在springBoot2.2版本之前的,测试采用的是junit4,在之后的版本(包括2.2.1及之后的版本)采用的为junit5;参考文章:
第三点:
因为自己使用的是1.5.9版本的springBoot版本, 所以 在springBoot实现测试需要的依赖包,只需要一个就可以实现测试了,如下:当然,如果加上junit4的包也是一样可以实现的;效果是一样的,spring-boot-starter-test是集成了junit4;org.springframework.boot spring-boot-starter-test test
正如上面所述的那样,如果是2.2版本之后的(包括2.2)引用官方的话,
引用官方的链接,如下:
25.测试
Spring
Boot提供了许多实用程序和注释,可以在测试应用程序时提供帮助。测试支持由两个模块提供:spring-boot-test包含核心项,并spring-boot-test-autoconfigure支持测试的自动配置。大多数开发人员都使用spring-boot-starter-test“入门程序”,该程序同时导入Spring Boot测试模块以及JUnit Jupiter,AssertJ,Hamcrest和许多其他有用的库。启动程序还带来了老式引擎,因此您可以运行JUnit 4和JUnit 5测试。如果已将测试迁移到JUnit 5,则应排除对JUnit 4的支持:
org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine
第四点:
如果是2.2之前的springBoot测试类,应该如下写:package springbootTest;import com.drillsb.springboot.SpringbootApplication;import com.drillsb.springboot.dao.CategoryDAO;import com.drillsb.springboot.pojo.Category;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)@SpringBootTest(classes = SpringbootApplication.class)public class Test1 { @Autowired CategoryDAO categoryDAO; @Test public void fun1(){ Listall = categoryDAO.findAll(); for (Category c : all) { System.out.println("当前对象名为; "+c.getName()); } } @Test public void fun2(){ System.out.println("hello junit?"); }}
如果是2.2之后的springBoot测试类,则只需要写一个@SpringBootTest即可,如下:
package springbootTest;import com.drillsb.springboot.SpringbootApplication;import com.drillsb.springboot.dao.CategoryDAO;import com.drillsb.springboot.pojo.Category;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@SpringBootTestpublic class Test1 { @Autowired CategoryDAO categoryDAO; @Test public void fun1(){ Listall = categoryDAO.findAll(); for (Category c : all) { System.out.println("当前对象名为; "+c.getName()); } } @Test public void fun2(){ System.out.println("hello junit?"); }}
使用jpa实现条件查询
要想实现jpa规范查询,那就得实现jpa接口,这里是在原来的springBoot中使用jpa实现增删改查基础上,进行条件查询的,详情看:
注意点
jpa实现条件查询,不需要自己写SQL语句; 只需要按照jpa的规范进行编写DAO方法就可以了,其规范如下: 其中,关于这个条件查询的博文写的不错:下面两个分别实现,根据name条件查询信息和根据name模糊查询,并且id大于某值,通过name升序;
在CategoryDAO中声明方法:
package com.drillsb.springboot.dao;import com.drillsb.springboot.pojo.Category;import org.springframework.data.jpa.repository.JpaRepository;import java.util.List;public interface CategoryDAO extends JpaRepository{ // 根据名字条件,查询信息 public List findByName(String name);// 根据name模糊查询,并且id大于某值,通过name升序 public List findByNameLikeAndIdGreaterThanOrderByNameAsc(String name,int id);}
然后查询,在测试类中,如下:
package springbootTest;import com.drillsb.springboot.SpringbootApplication;import com.drillsb.springboot.dao.CategoryDAO;import com.drillsb.springboot.pojo.Category;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)@SpringBootTest(classes = SpringbootApplication.class)public class Test1 { @Autowired CategoryDAO categoryDAO; @Test public void fun1(){ Listall = categoryDAO.findAll(); System.out.println("所有的分类信息:"); for (Category c : all) { System.out.println("当前对象名为: "+c.getName()+" 当前的对象id为: "+c.getId()); } System.out.println(); } @Test public void fun2(){ System.out.println("查询名称是 \"category 1 \"的分类:"); List cs = categoryDAO.findByName("category8"); for (Category category : cs) { System.out.println("查询出来的名字为category8的信息是: "); System.out.println("id为: "+category.getId()+"\n"+"name为: "+category.getName()); } System.out.println(); } @Test public void fun3(){ Category category; for (int i = 10; i < 20 ; i++) { category=new Category(); category.setName("category"+i); categoryDAO.save(category); } } @Test public void fun4(){ System.out.println("查询出name包括5,并且id大于10,按照名字升序排序"); List cs = categoryDAO.findByNameLikeAndIdGreaterThanOrderByNameAsc("%5%", 10); for (Category c : cs) { System.out.println(c); } }}
查询结果为:
在springBoot中实现上传文件
在springBoot中上传文件,使用的还是MultipartFile 这个类,这个类是由spring提供的,是一个接口,至于里面的方法,如下:
package org.springframework.web.multipart;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.nio.file.Files;import java.nio.file.Path;import org.springframework.core.io.InputStreamSource;import org.springframework.core.io.Resource;import org.springframework.lang.Nullable;import org.springframework.util.FileCopyUtils;public interface MultipartFile extends InputStreamSource { //getName() 返回参数的名称 String getName();//获取源文件的昵称 @Nullable String getOriginalFilename();//getContentType() 返回文件的内容类型 @Nullable String getContentType();//isEmpty() 判断是否为空,或者上传的文件是否有内容 boolean isEmpty();//getSize() 返回文件大小 以字节为单位 long getSize();//getBytes() 将文件内容转化成一个byte[] 返回 byte[] getBytes() throws IOException;//getInputStream() 返回InputStream读取文件的内容 InputStream getInputStream() throws IOException; default Resource getResource() { return new MultipartFileResource(this); }//transferTo(File dest) 用来把 MultipartFile 转换换成 File void transferTo(File var1) throws IOException, IllegalStateException; default void transferTo(Path dest) throws IOException, IllegalStateException { FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest)); }}
写两个jsp,用于上传文件和显示上传文件,如下:
uploadPage.jsp<%@ page contentType="text/html;charset=UTF-8" language="java" %>Title
showImg.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>Title
然后在新建一个UploadController,如下:
package com.drillsb.springboot.web;import com.sun.org.apache.xpath.internal.operations.Mod;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;import java.io.File;import java.io.IOException;@Controllerpublic class UploadController { /* * 因为是在WEB-INF下的jsp页面, * 不能够直接写该jsp页面进行访问,因而言 * 需要写一个访问地址,跳转到这个页面 * */ @RequestMapping("/uploadPage") public String uploadPage(){ return "uploadPage"; } @RequestMapping(value = "/upload",method = RequestMethod.POST) public String upload(HttpServletRequest request, @RequestParam("file") MultipartFile file, Model m){ // 定义上传文件的文件名 String fileName = System.currentTimeMillis() + file.getOriginalFilename(); /* * 这个File.separator==/ * */// 定义上传文件的存放目录以及名字 String destDirectoryAndName=request.getServletContext().getRealPath("/")+ "uploaded"+ File.separator+fileName; System.out.println("这个定义的上传文件地址是: "+destDirectoryAndName); File f=new File(destDirectoryAndName); f.getParentFile().mkdirs(); try { file.transferTo(f); } catch (IOException e) { System.out.println("上传失败: "+e.getMessage()); } m.addAttribute("fileName",fileName); System.out.println("该文件的地址在: "+f.getAbsolutePath()); return "showImg"; }}
然后启动,访问/uploadPage这个地址,之后选择图片,上传之后就会显示刚刚上传的图片;
遗留的问题
这里有一个问题,就是这个request.getServletContext().getRealPath("/")这个在springBoot中,获取到的不是项目的webapp下的地址,而是类似于这样的地址:C:\Users\zj\AppData\Local\Temp\tomcat-docbase.3199774529618517383.8080\uploaded\1611492518704
也就是说是一个临时文件地址。。。。唉,这个伤脑筋。。。暂时没有解决。。。。
在springBoot中使用restful
关于这个风格,有一篇博文整理了一些链接内容很好
博文地址:定义
restful风格就是能够实现,访问同一个地址,但是仍然做到实现不同的业务,如下: 这个使用restful中是基于jpa规范,使用hibernate实现持久层,持久层的实现在 已经说了如何实现,不赘述;修改listCategory.jsp,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>Title
修改editCategory.jsp,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>editCategory <%-- 原有的风格--%> <%-- --%><%-- restful的风格--%>
视图层注意点
a.超链接查询不修改提交方式
根据上面的restful表格可知:
get:用于查询 post:用于增加 put:用于修改 delete:删除所以与查询有关的都是使用get,且因为超链接的提交方式是get,所以与查询相关的超链接都不用修改其提交方式
b.超链接的书写形式
在常规的书写形式中,超链接带参数是:通过?后面加上参数名=参数值这种形式实现,也就是如下:
编辑
在restful中的书写形式是通过 **/**来实现的,也就是如下:
删除
c.让超链接提交方式为post、put、delete
因为要使超链接,也能够实现提交post,put,delete;所以也要修改其提交方式,而修改其提交方式通过表单这个中间的桥梁实现;
所以上面实现删除功能的时候,是通过表单,隐藏域,jquery实现的!表单:
在上面有一个隐藏input的表单,如下:
在这个表单中,input的name属性,跟value属性是不能乱写的! 回忆一下在原有的ssm或者mvc项目中,实现restful风格,是需要在web.xml中配置一个Spring的隐藏http方法拦截器的类, 该类为:HiddenHttpMethodFilter 其中在web.xml中配置为:
HiddenHttpMethodFilter org.springframework.web.filter.HiddenHttpMethodFilter methodParam _method HiddenHttpMethodFilter /*
这里的参数值:_method
就是跟隐藏域的name相对应的而springBoot因为已经集成好了,所以不需要写这个HiddenHttpMethodFilter
所以,这个隐藏input的name必须要为_method至于这个value,那么就可以写你想要改变的超链接需要的功能,post,put,delete都可以;
Jquey
其中为了改变其原有删除功能,使用了JQuery,如下:然后操作元素对象,采用Jquery实现的;
在springBoot中导入资源文件,有一点很重要,就是不需要按照相对路径的模式去写,如上面的JQuery引入,如下:因为我在webapp中添加了一个js文件夹,然后将资源放进去的,如下:
所以我一开始的错误的写法是这样的:但是根本没有实现引用JQuery文件
这是因为之前在springBoot基础(一)中的pom.xml已经配置好了路径,spring会扫描所以我一开始就写错了;再者,在springBoot中,有一些是默认可以存放静态资源的,如下: 该截图来源于博文:也就是说,将JQuery放到resources下面的static中也是可以的!也是不需要按照相对路径的模式写。
其中一些知识点,参考博文
修改完视图层,然后修改CategoryController,如下:
package com.drillsb.springboot.web;import com.drillsb.springboot.dao.CategoryDAO;import com.drillsb.springboot.pojo.Category;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;@Controllerpublic class CategoryController { @Autowired CategoryDAO categoryDAO;/*// 这个是查询该Category表的所有内容 @RequestMapping("/list") public String listCategory(Model m){ Listcs = categoryDAO.findAll(); m.addAttribute("cs",cs); return "listCategory"; }*/ @GetMapping("/categories") public String listCategory(Model m, @RequestParam(value = "start",defaultValue = "0")int start, @RequestParam(value = "size",defaultValue = "5")int size){ // 当在首页的时候,再点击上一页的情况下 start=start<0?0:start; Sort sort = new Sort(Sort.Direction.DESC, "id"); Pageable pb=new PageRequest(start,size,sort); Page page = categoryDAO.findAll(pb);// 遍历当前页面的分页的数据,返回为list数据,这里就是返回Category的集合 System.out.println(page.getContent().toString());// 获取当前页面数 System.out.println("当前第几页,总是非负的: "+page.getNumber()); System.out.println("返回当前页上的元素数: "+page.getNumberOfElements()); System.out.println("返回当前页面的大小: "+page.getSize()); System.out.println("返回元素总数: "+page.getTotalElements());// 获取总页面数 System.out.println("返回分页总数: "+page.getTotalPages()); m.addAttribute("page",page); return "listCategory"; } /* * 添加和修改都是使用save,其是根据实体类的id * 是否为0来判断是进行添加还是修改 * */// 添加 @PostMapping("/categories") public String addCategory(Category category){ categoryDAO.save(category); return "redirect:/categories"; }// 删除 @DeleteMapping("/categories/{id}") public String deleteCategory(Category category){ categoryDAO.delete(category); return "redirect:/categories"; }// 修改 @PutMapping("/categories/{id}") public String updateCategory(Category category){ categoryDAO.save(category); return "redirect:/categories"; }// 通过id获取到某一分类的信息 @GetMapping("/categories/{id}") public String getCategory(@PathVariable("id") int id,Model m){ // 通过id获取到表信息 Category c = categoryDAO.getOne(id); m.addAttribute("c",c); return "editCategory"; }}
控制层注意点
从上面的代码,可以看到,除了访问jsp页面以外,无论是修改,删除还是添加都是使用重定向访问categories;
为啥?操作之后不可以直接访问categories吗?
之前统一将访问的地址改为categories,所以每一次修改,删除,添加都得是重定向访问categories; 因为如果不是重定向,那么spring会默认为转发,转发的话会将categories当做是jsp(之前在application.properties中配置了),也就是会变成访问:http://localhost:8080/WEB-INF/jsp/categories.jsp
这很明显,是错误的。。。因为没有这个页面,会报404;
在springBoot中使用json
是在上面使用restful的风格下,进行的使用json;
首先在实体类中添加toString方法,并且加上@JsonIgnoreProperties注解,如下:package com.drillsb.springboot.pojo;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;import javax.persistence.*;@Entity@Table(name="category_")/** 将这个注解写在类上之后,就会忽略类中不存在的字段。* 这个注解还可以指定要忽略的字段* //不写这个就会报错,@JsonIgnoreProperties就是标注 哪个属性 不用转化为json的* */@JsonIgnoreProperties({ "handler","hibernateLazyInitializer" })public class Category { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="id") private int id; @Column(name="name") private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Category{" + "id=" + id + ", name='" + name + '\'' + '}'; }}
具体这个注解,参考了两篇博文,如下:
然后编写两个页面,一个submit.html
是向服务端提交数据,也是采用了JQuery的方式,如下:用ajax以json方式提交数据
还有一个是从服务端获取数据,如下:
用AJAX以JSON方式获取数据 通过AJAX获取到的一个Category对象为:
通过AJAX获取到的多个Category对象为:
然后在Controller中写一个java类,类CategoryJsonController,如下:
package com.drillsb.springboot.web;import com.drillsb.springboot.dao.CategoryDAO;import com.drillsb.springboot.pojo.Category;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.*;import java.util.List;@RestControllerpublic class CategoryJsonController { @Autowired CategoryDAO categoryDAO;// 这个是获取多个Category对象数据 @GetMapping("/category") @ResponseBody public ListlistCategory(@RequestParam(value = "start", defaultValue = "0") int start, @RequestParam(value = "size", defaultValue = "5") int size) throws Exception { start = start<0?0:start; Sort sort = new Sort(Sort.Direction.DESC, "id"); Pageable pageable = new PageRequest(start, size, sort); Page page =categoryDAO.findAll(pageable); return page.getContent(); }// 这个是获取一个Category对象的数据 @GetMapping("/category/{id}") @ResponseBody public Category getCategory(@PathVariable("id") int id) throws Exception { Category c= categoryDAO.getOne(id); System.out.println(c); return c; }// 这个是ajax提交过来的数据 @PutMapping("/category") public void addCategory(@RequestBody Category category) throws Exception { System.out.println("springboot接受到浏览器以JSON格式提交的数据:"+category); }}
在springBoot中使用Redis
redis的话,首先得有,大家自行下载。。。直接去官方勒,百度一下就完事;然后还可以下载一个图形化界面,这里推荐一个,如下:
首先得把redis服务器启动起来,如下:
启动之后,才是java代码的编写;因为是使用基于注解的缓存,所以有几个注解需要先学习,参考博文,如下:还有SpEL表达式的了解,如下:
添加对redis支持的依赖,如下:
org.springframework.boot spring-boot-starter-data-redis
同时配置application.properties,让能够显示sql语句,如下:
#将SQL语句显示出来spring.jpa.show-sql=true
在主程序运行类中,添加对注解缓存的支持,如下:
package com.drillsb.springboot;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cache.annotation.EnableCaching;@SpringBootApplication//表示这是一个springboot项目@EnableCaching //这个注解表示开启缓存public class SpringbootApplication { public static void main(String[] args) { SpringApplication.run(SpringbootApplication.class, args); }}
配置一个Redis缓存配置类,如下:
package com.drillsb.springboot.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;import com.fasterxml.jackson.annotation.PropertyAccessor;import com.fasterxml.jackson.databind.ObjectMapper;import org.springframework.cache.CacheManager;import org.springframework.cache.annotation.EnableCaching;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.RedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer;/** * redis缓存配置类 * 作用:让保存到 Redis 里的 key 和 value 都转换为可读的 json 格式 * 不然就会是二进制格式 */@Configuration@EnableCachingpublic class RedisConfig { @Bean public CacheManager cacheManager(RedisTemplate redisTemplate){ // 设置序列化类,第一个是key的序列化类 RedisSerializer stringSerializer=new StringRedisSerializer();// 第二个是value的序列化类 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);// 设置key类型 ObjectMapper om=new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY);// 使用指定的类型 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om);// 设置key的序列化 redisTemplate.setKeySerializer(stringSerializer);// 设置hashkey的序列化 redisTemplate.setHashKeySerializer(stringSerializer);// 设置value的序列化 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); CacheManager cacheManager=new RedisCacheManager(redisTemplate); return cacheManager; }}
再配置一个支持redis的分页Page类,因为原有的springBoot中的Page类,对分页不支持。就是创建一个类,该类拥有的Page类的大部分字段,如下:
package com.drillsb.springboot.util;import org.springframework.data.domain.Page;import java.util.List;public class Page4Navigator{ Page page4jpa; int navigatePages; int totalPages; int number; long totalElements; int size; int numberOfElements; List content; boolean isHasContent; boolean first; boolean last; boolean isHasNext; boolean isHasPrevious; int[] navigatepageNums; public Page4Navigator() { //这个空的分页是为了 Redis 从 json格式转换为 Page4Navigator 对象而专门提供的 } public Page4Navigator(Page page4jpa,int navigatePages) { this.page4jpa = page4jpa; this.navigatePages = navigatePages; totalPages = page4jpa.getTotalPages(); number = page4jpa.getNumber() ; totalElements = page4jpa.getTotalElements(); size = page4jpa.getSize(); numberOfElements = page4jpa.getNumberOfElements(); content = page4jpa.getContent(); isHasContent = page4jpa.hasContent(); first = page4jpa.isFirst(); last = page4jpa.isLast(); isHasNext = page4jpa.hasNext(); isHasPrevious = page4jpa.hasPrevious(); } public int getNavigatePages() { return navigatePages; } public void setNavigatePages(int navigatePages) { this.navigatePages = navigatePages; } public int getTotalPages() { return totalPages; } public void setTotalPages(int totalPages) { this.totalPages = totalPages; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public long getTotalElements() { return totalElements; } public void setTotalElements(long totalElements) { this.totalElements = totalElements; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getNumberOfElements() { return numberOfElements; } public void setNumberOfElements(int numberOfElements) { this.numberOfElements = numberOfElements; } public List getContent() { return content; } public void setContent(List content) { this.content = content; } public boolean isHasContent() { return isHasContent; } public void setHasContent(boolean isHasContent) { this.isHasContent = isHasContent; } public boolean isFirst() { return first; } public void setFirst(boolean first) { this.first = first; } public boolean isLast() { return last; } public void setLast(boolean last) { this.last = last; } public boolean isHasNext() { return isHasNext; } public void setHasNext(boolean isHasNext) { this.isHasNext = isHasNext; } public boolean isHasPrevious() { return isHasPrevious; } public void setHasPrevious(boolean isHasPrevious) { this.isHasPrevious = isHasPrevious; } public int[] getNavigatepageNums() { return navigatepageNums; } public void setNavigatepageNums(int[] navigatepageNums) { this.navigatepageNums = navigatepageNums; }}
增加Service接口,如下:
package com.drillsb.springboot.service;import com.drillsb.springboot.pojo.Category;import com.drillsb.springboot.util.Page4Navigator;import org.springframework.data.domain.Pageable;public interface CategoryService { public Page4Navigatorlist(Pageable pageable); public void save(Category category); public void delete(int id); public Category get(int id);}
以及实现类,如下:
package com.drillsb.springboot.service.impl;import com.drillsb.springboot.dao.CategoryDAO;import com.drillsb.springboot.pojo.Category;import com.drillsb.springboot.service.CategoryService;import com.drillsb.springboot.util.Page4Navigator;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cache.annotation.CacheConfig;import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.CachePut;import org.springframework.cache.annotation.Cacheable;import org.springframework.data.domain.Page;import org.springframework.data.domain.Pageable;import org.springframework.stereotype.Service;@Service@CacheConfig(cacheNames = "category")//表示缓存数据存储到名为category中public class CategoryServiceImpl implements CategoryService { /* * 首先要了解几个注解的意思 * @Cacheable注解: * 主要针对方法配置 * 会先查询是否已经有缓存,有会使用缓存,没有则会执行方法并缓存 * 参数值有: * value:缓存的名称 * key:缓存的键,指定要按照spEL表达式编写;缺省按照方法上所有参数进行组合 * condition:缓存的条件, * unless, 否定缓存 * allEntries 是否清空所有缓存,如果为true则方法调用后清空所有缓存 * * @CachePut注解的作用: * 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 * 和@Cacheable对比来说,这个既调用方法又更新缓存 * * @CacheConfig这个就是代替Cacheable注解将,value值统一为category * 当然,如果方法上还有Cacheable注解,那么以方法上的为主 * * */ /* * 注意: 1.当我们要使用root对象的属性作为key时我们也可以将“#root”省略, * 因为Spring默认使用的就是root对象的属性。 如 @Cacheable(key = "targetClass + methodName +#p0") 2.使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 * 如: @Cacheable(value="users", key="#id") @Cacheable(value="users", key="#p0") * */ @Autowired CategoryDAO categoryDAO; /* * 假如是第一页,即offset=0,pageSize=5, * 那么会创建一个 key: "category 0-5" * */ @Override @Cacheable(key = "'category'+#p0.offset+'-'+#p0.pageSize") public Page4Navigatorlist(Pageable pageable) { Page pageFromJPA = categoryDAO.findAll(pageable); Page4Navigator page=new Page4Navigator<>(pageFromJPA,5); return page; } /* * 注意这里,不能使用 * @CachePut * 因为这个有缺陷。。。要是缓存的key键 * 也就是存储在redis数据库中的key不一致,就会导致查询的key不一样 * 导致取不出来; * * 而这里。。。。恰恰每一个key都是不一样的。。。。 * */ @Override @CacheEvict(allEntries = true)//清理该分组下所有缓存,这里就是category这个缓存名下所有缓存 public void save(Category category) { categoryDAO.save(category); } @Override @CacheEvict(allEntries = true) public void delete(int id) { categoryDAO.delete(id); } @Override @Cacheable(key = "'category'+#p0") public Category get(int id) { Category c = categoryDAO.findOne(id); return c; }}
然后就是Controller类,如下:
package com.drillsb.springboot.web;import com.drillsb.springboot.pojo.Category;import com.drillsb.springboot.service.CategoryService;import com.drillsb.springboot.util.Page4Navigator;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;@Controllerpublic class CategoryRedisController { @Autowired CategoryService categoryService; @RequestMapping("/listRedisCategory") public String listCategory(Model m, @RequestParam(value = "start", defaultValue = "0")int start, @RequestParam(value = "size", defaultValue = "5")int size){ start=start<0?0:start; Sort sort=new Sort(Sort.Direction.DESC,"id"); Pageable pageable=new PageRequest(start,size,sort); Page4Navigatorpage = categoryService.list(pageable); m.addAttribute("page",page); return "listRedisCategory"; } @RequestMapping("/addRedisCategory") public String addCategory(Category category){ categoryService.save(category); return "redirect:listRedisCategory"; } @RequestMapping("/deleteRedisCategory") public String deleteCategory(Category category){ categoryService.delete(category.getId()); return "redirect:listRedisCategory"; } @RequestMapping("/editRedisCategory") public String editCategory(int id,Model m) throws Exception { Category c= categoryService.get(id); m.addAttribute("c", c); return "editRedisCategory"; } @RequestMapping("/updateRedisCategory") public String updateCategory(Category c) throws Exception { categoryService.save(c); return "redirect:listRedisCategory"; }}
页面重写了两个,并且没有采用restful风格;
一个是listRedisCategory.jsp页面,如下:<%@ page contentType="text/html;charset=UTF-8" language="java" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>Title
另一个是editRedisCategory.jsp,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>editCategory
重启springBoot主类,然后可以看到如下界面:
看起来没啥不同。。。。但是当我们打开图形化界面就可以看到:分页数据全都在缓存中,0-5条数据和5-5的数据都在这里,也就是首页下一页数据都在这里,然后当我们在首页的时候点击下一页,就可以看到在控制台并没有打印SQL语句,说明就是从Redis缓存中取的!
在springBoot中使用elasticsearch
因为使用的springBoot版本是1.5.9版本,所以其连接各种数据库的组件spring data也是1.5.9版本的,为了兼容性着想,其elasticsearch的版本也使用低版本的,这样会更好;
采用的elasticsearch版本是2.4.2,然后Kibana版本是4.6.3版本;兼容性,有一张表来自可以对比,如下: 老的对应版本如下:注意
这个整合使用,并没有用到elasticsearch的搜索功能,而是使用到其数据库的功能;首先打开2.4.2版本的bat文件,这个步骤在中安装elasticsearch已经说了,不赘述啦,然后打开如下:
之后添加依赖在pom.xml,如下:
4.0.0 org.springframework.boot spring-boot-starter-parent 1.5.9.RELEASE com.drillsb springboot 0.0.1-SNAPSHOT springboot war Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test javax.servlet javax.servlet-api javax.servlet jstl org.apache.tomcat.embed tomcat-embed-jasper org.mybatis.spring.boot mybatis-spring-boot-starter 1.1.1 org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-data-elasticsearch org.springframework.boot spring-boot-maven-plugin src/main/webapp META-INF/resources **/*.*
在application.properyies配置elasticsearch的端口,以及elasticsearch中jar包通讯连接端口9300,如下:
spring.mvc.view.prefix=/WEB-INF/jsp/spring.mvc.view.suffix=.jsserver.port=8080spring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300
然后配置实体类CategoryES,如下:
package com.drillsb.springboot.pojo;import org.springframework.data.elasticsearch.annotations.Document;/** 该类为使用elasticsearch为数据库的实体类* */@Document(indexName = "drillsb",type = "category")//创建索引名为drillsb,类型为categorypublic class CategoryES { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
DAO类,如下:
package com.drillsb.springboot.dao;import com.drillsb.springboot.pojo.CategoryES;import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;/* * 这是使用elasticsearch接口 * */public interface CategoryESDAO extends ElasticsearchRepository{ }
只是实现crud的话,并没有使用Service类了,所以直接在Controller类中调用DAO类,如下CategoryESController:
package com.drillsb.springboot.web;import com.drillsb.springboot.dao.CategoryESDAO;import com.drillsb.springboot.pojo.CategoryES;import org.elasticsearch.index.query.QueryBuilders;import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;import org.springframework.data.elasticsearch.core.query.SearchQuery;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import java.text.SimpleDateFormat;import java.util.Date;/** 这个是elasticsearch的控制类* */@Controllerpublic class CategoryESController { @Autowired CategoryESDAO categoryESDAO; @GetMapping("/listESCategory") public String listCategory(Model m, @RequestParam(value = "start",defaultValue = "0") int start, @RequestParam(value = "size",defaultValue = "5") int size){ SearchQuery searchQuery = getEntitySearchQuery(start, size); Pagepage = categoryESDAO.search(searchQuery); m.addAttribute("page",page); return "listESCategory"; } private SearchQuery getEntitySearchQuery(int start,int size){ QueryBuilder queryBuilder=QueryBuilders.matchAllQuery();// 设置分页 Sort sort =new Sort(Sort.Direction.DESC,"id"); Pageable pageable=new PageRequest(start,size,sort); return new NativeSearchQueryBuilder(). withPageable(pageable). withQuery(queryBuilder).build(); } @RequestMapping("/addESCategory") public String addCategory(CategoryES categoryES){ int id = currentTime(); categoryES.setId(id); categoryESDAO.save(categoryES); return "redirect:listESCategory"; }// 设置该表的id为当前时间的int值 private int currentTime(){ SimpleDateFormat sdf=new SimpleDateFormat("MMddHHmmss"); String time = sdf.format(new Date()); return Integer.parseInt(time); } @RequestMapping("/deleteESCategory") public String deleteCategory(CategoryES categoryES){ categoryESDAO.delete(categoryES); return "redirect:listESCategory"; } @RequestMapping("/updateESCategory") public String updateCategory(CategoryES categoryES){ categoryESDAO.save(categoryES); return "redirect:listESCategory"; } @RequestMapping("/editESCategory") public String editCategory(int id,Model m) { CategoryES c= categoryESDAO.findOne(id); m.addAttribute("c", c); return "editESCategory"; }}
之后就是准备好显示层了,跟前面的一样,只是没有使用restful风格,如下:
listESCategory.jsp:<%@ page contentType="text/html;charset=UTF-8" language="java" %><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>Title
editESCategory.jsp如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>editCategory
然后就是主程序类:
最后在springBoot的主程序类,一定要在 @SpringBootApplication()括号里面加上排除说明,不然会一直报以下的错误:o.s.b.d.LoggingFailureAnalysisReporter
这个错误是,当我们配置了elasticsearch作为数据源的时候,springBoot还是会去加载默认的数据源配置类,因为没有配置,所以会报LoggingFailureAnalysisReporter 错误,所以要配置如下;
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class})
主程序类为:
package com.drillsb.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.cache.annotation.EnableCaching;//@SpringBootApplication//表示这是一个springboot项目@EnableCaching //这个注解表示开启缓存@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class})public class SpringbootApplication { public static void main(String[] args) { SpringApplication.run(SpringbootApplication.class, args); }}
最后,点击运行主程序类,访问http://localhost:8080/listESCategory?start=0,显示是空的,然后需要自己添加几条数据,下面是我添加数据后:
使用Kibana访问
数据已经在drillsb索引中了,所以使用Kibana访问下,安装了4.6.3版本,然后打开bat文件,如下:
注意: 要先关闭前面在idea中运行的主程序,因为使用API连接的elasticsearch,要是不关闭,再使用Kibana连接elasticsearch,在idea就会报错:org.elasticsearch.transport.ReceiveTimeoutTransportException
这个报错参考博文:
之后访问http://127.0.0.1:5601,
如下: 因为是新安装的,所以没有索引,但是因为之前我们在实体类中已经创建了drillsb索引,所以这里我们指定索引:- 把默认勾选的 Index contians time-based evens 去掉
- 输入 drillsb
- 点击 Create 按钮
然后点击上面的Discover,加载一会如下:
右边显示了之前创建文档信息,这样就成功了! ps:如果点击Discover加载不出来,那就重新访问之后应该没问题;转载地址:https://blog.csdn.net/qq_45321679/article/details/113062909 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!