博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springBoot基础(二)
阅读量:3962 次
发布时间:2019-05-24

本文共 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实现测试需要的依赖包,只需要一个就可以实现测试了,如下:

org.springframework.boot
spring-boot-starter-test
test
当然,如果加上junit4的包也是一样可以实现的;效果是一样的,spring-boot-starter-test是集成了junit4;

正如上面所述的那样,如果是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(){
List
all = 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(){
List
all = 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方法就可以了,其规范如下:

blog.csdnimg.cn/20210124165716649.png)

在这里插入图片描述

其中,关于这个条件查询的博文写的不错:

下面两个分别实现,根据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(){
List
all = 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    
<%-- page.content获取到Category的数据--%>
<%-- 原有风格--%> <%--
--%><%-- restful风格--%>
id name 编辑 删除
${c.id} ${c.name} 编辑 删除 编辑 删除
<%-- 这是原有的风格--%> <%--
name:
--%><%-- 使用restful后--%>
name:

修改editCategory.jsp,如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>    editCategory
<%-- 原有的风格--%> <%--
name:
--%><%-- restful的风格--%>
name:

视图层注意点

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){ List
cs = 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方式提交数据
id:
名称:

还有一个是从服务端获取数据,如下:

    
用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 List
listCategory(@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 Page4Navigator
list(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 Page4Navigator
list(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); Page4Navigator
page = 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    
<%-- page.content获取到Category的数据--%>
id name 编辑 删除
${c.id} ${c.name} 编辑 删除
name:

另一个是editRedisCategory.jsp,如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>    editCategory
name:

重启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); Page
page = 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    
<%-- page.content获取到Category的数据--%>
id name 编辑 删除
${c.id} ${c.name} 编辑 删除
name:

editESCategory.jsp如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>    editCategory
name:

然后就是主程序类:

最后在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索引,所以这里我们指定索引:

  1. 把默认勾选的 Index contians time-based evens 去掉
  2. 输入 drillsb
  3. 点击 Create 按钮

然后点击上面的Discover,加载一会如下:

在这里插入图片描述
右边显示了之前创建文档信息,这样就成功了!

ps:如果点击Discover加载不出来,那就重新访问之后应该没问题;

转载地址:http://ucgzi.baihongyu.com/

你可能感兴趣的文章
O(logn)时间复杂度求Fibonacci数列
查看>>
【转】腾讯十年运维老兵:运维团队的五个“杀手锏”
查看>>
Iterator_traits
查看>>
Zedboard中的SPI通信记录文档(已实现)
查看>>
zigbee学习笔记2----cc2530 IO实验
查看>>
zigbee学习笔记4----初次接触zstack
查看>>
Android 发布到google Play的app搜索不到问题的解决
查看>>
Flutter 网络请求之基于dio的简单封装
查看>>
Flutter UI基础 - 路由之Navigator详解
查看>>
Flutter UI基础 - Widgets 之 InkWell 和 Ink
查看>>
Spring - sentinel和hystrix比较
查看>>
MySQL - 索引之B+树
查看>>
Spring - Dubbo的底层实现原理和机制
查看>>
Flutter Dio引入和简单的Get/Post请求
查看>>
Flutter Dart 和 Flutter json转实体类(插件自动生成)
查看>>
Flutter 路由跳转fluro
查看>>
Flutter 日期插件date_format 中文 国际化 及flutter_cupertino_date_picker
查看>>
Flutter 插件笔记 | 屏幕适配 flutter_screenutil
查看>>
Flutter UI基础 - 侧拉抽屉菜单
查看>>
Flutter UI基础 - AppBar中标题文字如何居中
查看>>