理论和实践总是有差距的,spring boot实战开始
一、前提:根据网址http://www.ityouknow.com/springboot/2016/01/06/spring-boot-quick-start.html 开启springboot的练习
二、问题记录:
1、打开https://start.spring.io,不做更改,简单下载了一个demo项目框架,解压,用intellij idea打开后,重写了实例中的HelloController,结果按照http://localhost:8080/hello 访问发现有问题如下:
对应问题,当前项目结构如下
解决:根据问题搜索,发现问题原因:
https://www.cnblogs.com/lilinzhiyu/p/7921890.html
于是将hellocontroller.java文件移动到了和DemoApplication相同的包,访问结果ok,因此,特别注意文中所说的结构问题:
即自己创建的包必须作为子包放在启动目录包下。
于是最新的结构为:
注:因为spring jpa的自动映射功能,数据库连接时,只需要在mysql数据库中创建一个数据库,即可。不需要手动创建表,
当你通过entity实体类创建完实体,通过对实体类(bean)添加@Entity 注解和@Table(name = "数据库中欲创建的表名”) 注解,
正常运行spring boot项目,则数据库中会自动创建相应的表。
相关关键类和配置如下(注:因为该博客是在完成一定量的基础上记录的,后面会尽可能按照当初的步骤记录):
如上左侧为当前状态,正常刚开始的时候,只有一个启动类和pom文件部分内容:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.4.RELEASE
com.example
demo
0.0.1-SNAPSHOT
demo
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-web
RELEASE
compile
junit
junit
4.12
test
org.springframework.boot
spring-boot-devtools
mysql
mysql-connector-java
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-maven-plugin
创建一个controller的包,在其中创建一个HelloController类,即可完成初步的spring boot的hello world意思的功能
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/welcome") //
public String index(){
return "Spring boot welcome to you !";
}
}
此时已经可以试验,通过直接启动运行,在浏览器中输入如下地址即可http://localhost:8080/welcome
效果即:
到此第一个helloworld类型的测试就ok了
三、接下来验证一般的java web项目的创建基本环境添加配置如下:
application.properties
#通用数据源配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver //mysql不同版本驱动类型有别
spring.datasource.url=jdbc:mysql://localhost:3306/sbootmysql?useUnicode=true&characterEncoding=utf8&serverTimezone=CST //注意serverTimezone的配置
spring.datasource.username=root
spring.datasource.password=youpassword
#http编码设置
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
#thymeleaf 视图解析配置
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.check-template-location=true
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.mode=HTML5
# JPA 相关配置
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
#是否打印sql语句
spring.jpa.show-sql= true
类的内容如下:
基本的实体bean类,注意,在此创建了一个特殊的父类MappedSupperClass类型的父类,用于统一管理id,你也可以不创建,
该种方式为当前通用的一种简化写代码操作的方式,这样在子类中可以共享一些属性而无需自定义。
package com.example.demo.bean;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@MappedSuperclass //注意BaseBean添加该注解,
public class BaseBean {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)//配置的ID自增策略
private Long id;
}
package com.example.demo.bean;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.io.Serializable;
@Entity
@Table(name = "user")//此处报错,则说明是数据库未连接成功,请查看数据源的连接和配置
public class User extends BaseBean implements Serializable {
private String name;
private int age;
private String info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
Dao层很简单,对的,就是这么简单,这里的通用的commonDao 需要注意,此处是因为使用了spring JPA
package com.example.demo.dao;
import com.example.demo.bean.BaseBean;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CommonDao extends JpaRepository {
}
package com.example.demo.dao;
import com.example.demo.bean.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserDao extends CommonDao {
}
开始创建服务层相关类:
package com.example.demo.service;
import com.example.demo.bean.User;
import java.util.List;
public interface UserService {
/**
* 保存用户对象
* @param user
*/
void save(User user);
/**
* 查询所有用户信息
* */
List getUserList();
}
package com.example.demo.serviceimpl;
import com.example.demo.bean.User;
import com.example.demo.dao.UserDao;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public void save(User user) {
userDao.save(user);
}
@Override
public List getUserList() {
return userDao.findAll();
}
}
如下是提供给前端页面访问的controller层:
package com.example.demo.controller;
import com.example.demo.bean.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "hello world ,you happy";
}
@RequestMapping("/index")
public String index(Model model) {
model.addAttribute("name", "jack");
model.addAttribute("age", 20);
model.addAttribute("info", "我是一个爱学习的好青年");
return "index";
}
@RequestMapping("/save")
@ResponseBody
public String save(User user) {
userService.save(user);
return "save success !";
}
@RequestMapping("/userList")
public String userList(Model model) {
List userList = userService.getUserList();
model.addAttribute("userList", userList);
return "list";
}
}
前端使用了 thymeleaf,注意这里的thymeleaf类似于传统的jsp freemarker等模板。注意,这里的如下文件名和你controller层中方法的返回值的名称一样,比如接口返回index,则这里的文件名定义为index.html。注意接口的返回值和文件名相差一个.html。
并且,接口所在的controller层,上方标注需要的注解是普通的@Controller,不能是@RestController,否则只会返回index, 而不是当前期望的html页面。使用thymeleaf注意用在maven中引入。
Index
如上,基本的定义就好了,可以正常启动项目,进行接口访问。
特别注意,因为该项目使用了spring的 JPA,可以自动完成实体类与数据库表的自动映射,不需要手动创建表,但是要首先在mysql中创建一个数据库,完成如上方mysql的application.properties中关于数据源的相关定义。并且成功连接数据库,否则会出现各种问题,后面会附加一些个人在运行中遇到的一些问题及解决方案。
四、问题附加:
1、@Table(name = "user")爆红,提示 can't resolve table ,经搜索资料得知,mysql 数据库未成功连接上,
于是配置idea与mysql的连接,操作为:View——》Tool windows——》Database,然后选择+号,添加数据源,因为我的是mysql,根据界面提示,我idea中没有mysql驱动mysql-coonector-8.0.15-jar 于是点击Download,完成了mysql的驱动安装,之后根据提示,填写如下界面信息,最终效果如下图:
初始如下配置时,测试TestConnection,结果显示:
于是查询资料,配置application.properties文件如下:
#通用数据源配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sbootmysql?useUnicode=true&characterEncoding=utf8&serverTimezone=CST
spring.datasource.username=root
spring.datasource.password=youpassword
# Hikari 数据源专用配置
# JPA 相关配置
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
》如果 @Table(name = "user")还报错,请根据Assign datasouce 此处是否配置有问题,正常应该是有值,如果没有则说明数据库连接有问题:
点击如上下拉三角,应该有可选项,选择正确连接的数据源即可
点击确定按钮,界面会自动刷新,user下的红色波浪线会消失,否则请继续检查。
至此,配置成功。
后补:在进行jpa的多数据源配置过程中,发现通@Table(name = “user”) 类似的爆红问题,发现@Column(name = "id")爆红,
提示原因同上,因为之前的经验,确定是因为在idea连接mysql的配置过程中配置项少一项,serverTimezone未设置,当出现msyql数据库连接成功时,会在下图3的位置出现一个绿色的小对号,同时该问题被解决
五、与Junit相关的测试配置:
1、测试需要添加的相关配置,因为是Junit5,因为开始时删除了一些不知道的东西,后来出了很多错,发现这几个配置要注意加上
org.springframework.boot
spring-boot-starter-test
org.junit.platform
junit-platform-launcher
test
junit
junit
4.12
test
测试类如下:
package com.example.demo.controller;
import org.junit.Assert;
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.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@Before
public void setup(){
//1.初始化
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
@Test
public void userList() throws Exception {
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/userList").accept(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andReturn();
int status = mvcResult.getResponse().getStatus();
//ModelMap map = (ModelMap) mvcResult.getModelAndView().getModel();
//打印出状态码,200就是成功
// log.info("状态码="+status);
Assert.assertEquals(200, status);
// Assert.assertEquals(3, map);
}
}
其中遇到错误时查看的相关文档有:
https://bbs.csdn.net/topics/395053502
2、在进行spring boot jpa 与 Redis的结合单元测试时,
参考了http://www.ityouknow.com/springboot/2016/03/06/spring-boot-redis.html
redis连接配置环境如下:
application.properties 中配置如下:
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=自己redis服务器在的地址,如果是本地,则为127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=123456
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0
在src ——main——和bean包相同等级处创建了一个用于管理各种配置的config包,在其中存放各个模块的配置类。
为Redis创建了一个RedisConfig类,内容如下:
package com.example.demo.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
};
}
}
又创建了一个测试类,如下:
package com.example.demo.service;
import com.example.demo.bean.User;
import org.junit.Assert;
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.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class RedisTest {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate redisTemplate;
@Test
public void test() throws Exception {
stringRedisTemplate.opsForValue().set("aaa", "111");
Assert.assertEquals("111", stringRedisTemplate.opsForValue().get("aaa"));
}
@Test
public void testObj() throws Exception {
User user=new User();
user.setName("cesssssss");
user.setAge(88);
user.setInfo("我想要去上班");
ValueOperations operations=redisTemplate.opsForValue();
operations.set("com.neox", user);
operations.set("com.neo.f", user,1, TimeUnit.SECONDS);
Thread.sleep(1000);
//redisTemplate.delete("com.neo.f");
boolean exists=redisTemplate.hasKey("com.neo.f");
if(exists){
System.out.println("exists is true");
}else{
System.out.println("exists is false");
}
//Assert.assertEquals("aa", operations.get("com.neo.f").getUserName());
}
}
但是在此过程中出现了几个问题,参考的相关文档如下:
问题3:一个方法测试通过,另一个错误:
org.springframework.data.redis.serializer.SerializationException: Cannot serialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.example.demo.bean.User]
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:96)
at org.springframework.data.redis.core.AbstractOperations.rawValue(AbstractOperations.java:127)
at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:235)
at com.example.demo.service.RedisTest.testObj(RedisTest.java:37)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.example.demo.bean.User]
at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:68)
at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:35)
at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.serialize(JdkSerializationRedisSerializer.java:94)
... 33 more
Caused by: java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.example.demo.bean.User]
at org.springframework.core.serializer.DefaultSerializer.serialize(DefaultSerializer.java:43)
at org.springframework.core.serializer.support.SerializingConverter.convert(SerializingConverter.java:63)
... 35 more
解决方案参考了文章:https://www.cnblogs.com/han-1034683568/p/7994322.html
原因是,我的实体bean当时没有继承序列化接口:让 User类实现Serialiazeable 序列化接口即可。
4、问题是:
java.lang.Exception: No runnable methods
at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:191)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:128)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:416)
at org.junit.runners.ParentRunner.(ParentRunner.java:84)
at org.junit.runners.BlockJUnit4ClassRunner.(BlockJUnit4ClassRunner.java:65)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.(SpringJUnit4ClassRunner.java:137)
at org.springframework.test.context.junit4.SpringRunner.(SpringRunner.java:49)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
at org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder$DefensiveAnnotatedBuilder.buildRunner(DefensiveAllDefaultPossibilitiesBuilder.java:113)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder.runnerForClass(DefensiveAllDefaultPossibilitiesBuilder.java:56)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.vintage.engine.discovery.ClassSelectorResolver.resolveTestClass(ClassSelectorResolver.java:66)
at org.junit.vintage.engine.discovery.ClassSelectorResolver.resolve(ClassSelectorResolver.java:47)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.lambda$resolve$2(EngineDiscoveryRequestResolution.java:129)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1631)
at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:127)
at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:502)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.resolve(EngineDiscoveryRequestResolution.java:174)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.resolve(EngineDiscoveryRequestResolution.java:120)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.resolveCompletely(EngineDiscoveryRequestResolution.java:87)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.run(EngineDiscoveryRequestResolution.java:80)
at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolver.resolve(EngineDiscoveryRequestResolver.java:112)
at org.junit.vintage.engine.discovery.VintageDiscoverer.discover(VintageDiscoverer.java:42)
at org.junit.vintage.engine.VintageTestEngine.discover(VintageTestEngine.java:62)
at org.junit.platform.launcher.core.DefaultLauncher.discoverEngineRoot(DefaultLauncher.java:177)
at org.junit.platform.launcher.core.DefaultLauncher.discoverRoot(DefaultLauncher.java:164)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
正常运行完毕,会显示绿色,查看redis数据库,通过 keys * 可以看到数据库中增加了内容:
xxx.xx.xx.xxx:6379> Keys *
1) "\xac\xed\x00\x05t\x00\bcom.neox"
2) "username"
3) "aaa"
xxx.xx.xx.xxx:6379>
如上为手动为redis设置缓存,redis自动有缓存。我重新创建了一个RedisController,然后添加了方法,之后直接启动运行,访问浏览器,随后查看redis数据库内容进行验证:
package com.example.demo.controller;
import com.example.demo.bean.User;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RedisController {
@RequestMapping("/getUser")
@Cacheable(value="user-key")
public User getUser() {
User user=new User();
user.setInfo("爱我中华,抗疫必胜");
user.setAge(11);
user.setName("小雪");
System.out.println("若下面没出现“无缓存的时候调用”字样且能打印出数据表示测试成功");
return user;
}
}
xxx.xx.xx.xxx:6379> keys *
1) "\xac\xed\x00\x05t\x00\bcom.neox"
2) "username"
3) "user-key::com.example.demo.controller.RedisControllergetUser"
4) "aaa"
xxx.xx.xx.xxx:6379>
3、更改redis的配置,如失效时间等,此处需要引入相关依赖包:
org.springframework.session
spring-session-data-redis
创建一个redis的java配置文件
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class SessionConfig {
}
测试接口:
@RequestMapping("/uid")
String uid(HttpSession session) {
UUID uid = (UUID) session.getAttribute("uid");
if (uid == null) {
uid = UUID.randomUUID();
}
session.setAttribute("uid", uid);
return session.getId();
}
登录 Redis 输入 keys '*sessions*'
xxx.xx.xx.xxx:6379> keys '*sessions*'
1) "spring:session:sessions:expires:6517e1d7-24e7-470b-88bb-903299321058"
2) "spring:session:sessions:6517e1d7-24e7-470b-88bb-903299321058"
xxx.xx.xx.xxx:6379>
其中 1472976480000 为失效时间,意思是这个时间后 Session 失效,db031986-8ecc-48d6-b471-b137a3ed6bc4
为 sessionId,登录 http://localhost:8080/uid 发现会一致,就说明 Session 已经在 Redis 里面进行有效的管理了。
解决方案参考了文档:
https://blog.csdn.net/lansexiuzhifu/article/details/81413477
原因是 ,导错了包:
1.导错了包:@Test时import的是@org.testng.annotations.Test 所以会报错