一、目的
实验目的:
- 掌握Spring Boot搭建微服务的一般步骤,理解微服务体系架构。
实验要求:
- 独立完成实验操作,并撰写实验报告(实验报告模板见附件)。
实验内容:
- Spring Boot微服务框架搭建
- (1)设计项目框架,并确定微服务的划分逻辑,如api、model和server,或者api、service和server,或者其他的(不限微服务个数,但要合理)。
- (2)搭建实际项目(建议使用maven),并添加常用dependencies,如mysql、mybatis、log4j、lombok、jackson、redis等。
- (3)编写应用程序入口,测试并运行。
- (4)添加若干控制器,服务之间的调用遵循Restful风格,功能及入口地址自定,并测试所编写的功能。
- (5)注意:本实验搭建的Spring Boot框架将用于后续实验扩展,因此请认真完成!
二、实验内容与设计思想
2.1 设计思路
-
新建项目
-
构建api模块
-
构建service模块
-
构建server模块
-
引入各个依赖:dependencies,如mysql、mybatis、log4j、lombok、jackson、redis
-
在api中编写实体类
-
编写redisConfig和resConfig
-
在service和server中编写controller进行测试
2.2 主要数据结构
public class Course implements Serializable
{
private Integer id;
private String name;
private Date startTime;
private Date endTime;
private Double price;
private String introduction;
private String personId;
}
public class Diary implements Serializable
{
private Integer id;
private Integer courseId;
private Date startTime;
private String content;
private String title;
private String personId;
}
public class Order implements Serializable
{
private Integer id;
private Date startTime;
private String coupon;
private Double price;
private String evaluate;
private Integer evaluateStart;
private Integer courseId;
private Integer status;
private String personId;
}
public class Person implements Serializable
{
private String id;
private String nickname;
private String introduction;
private Integer age;
private String weight;
private Date joinTime;
private String email;
private String password;
private String image;
private Integer height;
private String sex;
private Integer role;
}
public class Revert implements Serializable
{
private Integer id;
private String content;
private Date startTime;
private Integer diaryId;
private String personId;
}
2.3 主要代码结构
└── api/
├── pom.xml
└── src/main/java/
└── domain/
├── Course.java
├── Diary.java
├── Order.java
├── Person.java
├── Revert.java
└── server/src/main/
└── java/com/example/server/
└── controller/
├── MyCourseController.java
├── MyDiaryController.java
├── MyOrderController.java
├── MyPersonController.java
├── MyRedisController.java
├── MyRevertController.java
└── demos/
└── web/
├── BasicController.java
├── PathVariableController.java
├── User.java
├── ServerApplication.java
└── util/
├── Config.java
├── RedisConfig.java
└── resources/
├── application.properties
└── service/src/main/
└── java/com/example/service/
└── controller/
├── CourseController.java
├── DiaryController.java
├── OrderController.java
├── PersonController.java
├── RevertController.java
└── mapper/
├── CourseMapper.java
├── DiaryMapper.java
├── OrderMapper.java
├── PersonMapper.java
├── RevertMapper.java
└── service/
├── CourseService.java
├── DiaryService.java
└── impl/
├── CourseServiceImpl.java
├── DiaryServiceImpl.java
├── OrderServiceImpl.java
├── PersonServiceImpl.java
├── RevertServiceImpl.java
├── OrderService.java
├── PersonService.java
├── RevertService.java
├── ServiceApplication.java
└── util/
├── CORSFilter.java
├── R.java
└── resources/
├── application.properties
└── mapper/
├── CourseMapper.xml
├── DiaryMapper.xml
├── OrderMapper.xml
├── PersonMapper.xml
├── RevertMapper.xml
└── src/
└── main/
2.4 主要代码段分析
service模块的controller示例:
@RestController
@RequestMapping("/course")
public class CourseController
{
@Resource
private CourseService courseService;
/**
* 全查询
*
* @param course 筛选条件
* @return 查询结果
*/
@GetMapping
public R queryAll(Course course)
{
return this.courseService.queryAll(course);
}
/**
* 新增数据
*
* @param course 实体
* @return 新增结果
*/
@PostMapping
public R add(@RequestBody Course course)
{
return this.courseService.insert(course);
}
/**
* 更新数据
*
* @param course 实体
* @return 更新结果
*/
@PutMapping
public R update(@RequestBody Course course)
{
return this.courseService.update(course);
}
/**
* 删除数据
*
* @param id 主键
* @return 删除是否成功
*/
@DeleteMapping
public R deleteById(Integer id)
{
return this.courseService.deleteById(id);
}
}
server的controller示例:
@RestController
@RequestMapping
public class MyCourseController
{
private final String URL_PREFIX = "http://localhost:8081";
@Resource
private RestTemplate restTemplate;
@GetMapping("/my/course")
public R testQueryAllCourse() {
return restTemplate.getForObject(URL_PREFIX + "/course", R.class);
}
@PostMapping("/my/course")
public R testAddCourse(@RequestBody Course course) {
return restTemplate.postForObject(URL_PREFIX + "/course", course, R.class);
}
@PutMapping("/my/course")
public R testUpdateCourse(@RequestBody Course course) {
return restTemplate.exchange(URL_PREFIX + "/course", HttpMethod.PUT, new HttpEntity<>(course), R.class).getBody();
}
@DeleteMapping("/my/course/{id}")
public R testDeleteCourse(@PathVariable Integer id) {
return restTemplate.exchange(URL_PREFIX + "/course?id=" + id, HttpMethod.DELETE, null, R.class).getBody();
}
}
三、实验使用环境
平台:win10
软件:idea
四、实验步骤和调试过程
4.1 实验步骤
-
新建项目,构建api模块,service模块,server模块
-
引入各个依赖:dependencies,如mysql、mybatis、log4j、lombok、jackson、redis
-
在api中编写实体类
public class Course implements Serializable
{
private Integer id;
private String name;
private Date startTime;
private Date endTime;
private Double price;
private String introduction;
private String personId;
}
public class Diary implements Serializable
{
private Integer id;
private Integer courseId;
private Date startTime;
private String content;
private String title;
private String personId;
}
public class Order implements Serializable
{
private Integer id;
private Date startTime;
private String coupon;
private Double price;
private String evaluate;
private Integer evaluateStart;
private Integer courseId;
private Integer status;
private String personId;
}
public class Person implements Serializable
{
private String id;
private String nickname;
private String introduction;
private Integer age;
private String weight;
private Date joinTime;
private String email;
private String password;
private String image;
private Integer height;
private String sex;
private Integer role;
}
public class Revert implements Serializable
{
private Integer id;
private String content;
private Date startTime;
private Integer diaryId;
private String personId;
}
- 编写redisConfig和resConfig
@Configuration
public class Config {
@Bean
public RestTemplate restTemplate()
{
return new RestTemplate();
}
}
@Configuration
public class RedisConfig
{
@Autowired(required = false)
private RedisConnectionFactory redisConnectionFactory;//Redis连接工厂(相当于redis-cli的窗口)
@Bean
public RedisTemplate<String, Object> redisTemplate()//相当于redis-cli的命令行
{
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
// redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());//JSON泛型
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
@Bean
public StringRedisTemplate stringRedisTemplate()
{
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
return stringRedisTemplate;
}
}
- 在service和server中编写controller进行测试
service模块的controller示例(代码太多,只放其中一个controller示例):
@RestController
@RequestMapping("/course")
public class CourseController
{
@Resource
private CourseService courseService;
/**
* 全查询
*
* @param course 筛选条件
* @return 查询结果
*/
@GetMapping
public R queryAll(Course course)
{
return this.courseService.queryAll(course);
}
/**
* 新增数据
*
* @param course 实体
* @return 新增结果
*/
@PostMapping
public R add(@RequestBody Course course)
{
return this.courseService.insert(course);
}
/**
* 更新数据
*
* @param course 实体
* @return 更新结果
*/
@PutMapping
public R update(@RequestBody Course course)
{
return this.courseService.update(course);
}
/**
* 删除数据
*
* @param id 主键
* @return 删除是否成功
*/
@DeleteMapping
public R deleteById(Integer id)
{
return this.courseService.deleteById(id);
}
}
server的controller示例(代码太多,只放其中一个controller示例):
@RestController
@RequestMapping
public class MyCourseController
{
private final String URL_PREFIX = "http://localhost:8081";
@Resource
private RestTemplate restTemplate;
@GetMapping("/my/course")
public R testQueryAllCourse() {
return restTemplate.getForObject(URL_PREFIX + "/course", R.class);
}
@PostMapping("/my/course")
public R testAddCourse(@RequestBody Course course) {
return restTemplate.postForObject(URL_PREFIX + "/course", course, R.class);
}
@PutMapping("/my/course")
public R testUpdateCourse(@RequestBody Course course) {
return restTemplate.exchange(URL_PREFIX + "/course", HttpMethod.PUT, new HttpEntity<>(course), R.class).getBody();
}
@DeleteMapping("/my/course/{id}")
public R testDeleteCourse(@PathVariable Integer id) {
return restTemplate.exchange(URL_PREFIX + "/course?id=" + id, HttpMethod.DELETE, null, R.class).getBody();
}
}
RedisController:
@RestController
@RequestMapping("/redis")
public class MyRedisController
{
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@GetMapping("/{key}")
public R getValue(@PathVariable String key)
{
System.out.println("get:key:" + key);
Object value = redisTemplate.opsForValue().get(key);
return R.ok().setData(value);
}
@GetMapping
public R getAllValue()
{
Set<String> keys = redisTemplate.keys("*");
keys.remove("name");
System.out.println("keys" + keys);
Map<String, Object> data = new HashMap<>();
if (keys != null)
{
for (String key : keys)
{
System.out.println(key);
Object value = redisTemplate.opsForValue().get(key);
data.put(key, value);
}
}
return R.ok().setData(data);
}
@PostMapping("/{key}")
public R addValue(@PathVariable String key, @RequestBody Object value)
{
try
{
System.out.println("post:key:" + key);
redisTemplate.opsForValue().set(key, value);
return R.ok().setData(true);
} catch (Exception e)
{
e.printStackTrace();
return R.exp().setData(e.getMessage());
}
}
@PostMapping("/{key}/{expirationInSeconds}")
public R setWithExpiration(@PathVariable String key, @PathVariable int expirationInSeconds, @RequestBody Object value)
{
try
{
System.out.println("post:key:" + key);
ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
valueOperations.set(key, value);
redisTemplate.expire(key, expirationInSeconds, TimeUnit.SECONDS);
return R.ok().setData(true);
} catch (Exception e)
{
e.printStackTrace();
return R.exp().setData(e.getMessage());
}
}
@DeleteMapping("/{key}")
public ResponseEntity<Void> deleteValue(@PathVariable String key)
{
System.out.println("delete:key:" + key);
redisTemplate.delete(key);
return ResponseEntity.noContent().build();
}
@PutMapping("/{key}")
public ResponseEntity<Void> updateValue(@PathVariable String key, @RequestBody Object value)
{
System.out.println("put:key:" + key);
if (redisTemplate.opsForValue().get(key) != null)
{
redisTemplate.opsForValue().set(key, value);
return ResponseEntity.noContent().build();
} else
{
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
}
4.2 测试数据设计
-
测试service各个controller的get,put,post,delete
-
测试service各个controller的get,put,post,delete
-
测试redisController的get,put,post,delete
4.3 测试结果分析
service的无参数GET测试:
- course类
![](https://img-blog.csdnimg.cn/img_convert/94e24dd7317ae7ec687e64b321cf9625.png)
- order类
![](https://img-blog.csdnimg.cn/img_convert/9f1e6095f64af304dd479eede9f8c645.png)
- person类
![](https://img-blog.csdnimg.cn/img_convert/f359d4859840ec473f821f4caf95a832.png)
- diary类
![](https://img-blog.csdnimg.cn/img_convert/9cb3589d1f77a5c30ed93cc30ca531fb.png)
-
revert类
service的带参数GET测试:
- course类
![](https://img-blog.csdnimg.cn/img_convert/ace58e5a176b86c776c35c86db8b51d2.png)
-
revert类
-
order类
-
diary类
-
person类
service的PUT测试:
-
course类
修改前:
修改后:
-
person类
修改前:
修改后:
-
diary类
修改前:
修改后:
-
order类
修改前:
修改后:
-
revert类
修改前:
修改后:
service的POST测试:
-
course类
错误测试:
正确测试:
-
person类
错误测试:
正确测试:
-
diary类
错误测试:
正确测试:
-
order类
错误测试:
正确测试:
-
revert类
错误测试:
正确测试:
service的DELETE测试:
-
course类
-
person类
-
diary类
因为外键约束所以无法删除
-
order类
-
revert类
server的GET测试
![](https://img-blog.csdnimg.cn/img_convert/e7c11da7011b0b0052ce895367a69e4b.png)
server的PUT测试
更新前:
![](https://img-blog.csdnimg.cn/img_convert/240a141cb4096a1f07662de2ead46395.png)
更新后:
![](https://img-blog.csdnimg.cn/img_convert/67126547a4eadc7b5aa7239376ce3c28.png)
server的POST测试
![](https://img-blog.csdnimg.cn/img_convert/17743c81ff81c6f86f24b0f44a026dd2.png)
server的DELETE测试
![](https://img-blog.csdnimg.cn/img_convert/bfdfebdf59c60287be62f3e9b561fc41.png)
删除成功
Redis的POST无时间测试
![](https://img-blog.csdnimg.cn/img_convert/4cff7aa3be1708b6466ae661e607edfb.png)
![](https://img-blog.csdnimg.cn/img_convert/ee23423f9e70a90335a2907623414386.png)
测试结果如下:
![](https://img-blog.csdnimg.cn/img_convert/844a0f994ce1fe1e9a21fcd86d1cf932.png)
Redis的POST时间测试
加入了10秒的时间限制
![](https://img-blog.csdnimg.cn/img_convert/efeb2425fd1bea10dd7acfe5aaf1a6bf.png)
post请求完毕后,进行get获取数据,可以看到testKey3出现了。
![](https://img-blog.csdnimg.cn/img_convert/2bfa606632ee3bd894fb212c3a095e09.png)
10秒后,可以看到testKey3又消失了。
![](https://img-blog.csdnimg.cn/img_convert/be08038f358028a3a7eabcc56beb8d71.png)
Redis的GET测试
![](https://img-blog.csdnimg.cn/img_convert/7fb58798fdbf92a9ce85593ba0b0180c.png)
Redis的PUT测试
![](https://img-blog.csdnimg.cn/img_convert/8c64bfb311647bc770407141b6a76235.png)
可以看到结果,已经更改了testKey2的键值:
![](https://img-blog.csdnimg.cn/img_convert/81e4095e7e34f02e8a58dee95c46c71f.png)
Redis的DELETE测试
![](https://img-blog.csdnimg.cn/img_convert/a2f48f9d295512cfc33f1f509fc738bc.png)
可以看到结果中testKey已经被删除:
![](https://img-blog.csdnimg.cn/img_convert/c2f67f2c8dc44a5f93da464cc75b3f48.png)
五、实验小结
- 实验中遇到的问题及解决过程
无 - 实验中产生的错误及原因分析
无 - 实验体会和收获。
无