增加项目说明
@ -45,9 +45,9 @@ spring-cloud:Finchley.SR2
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| [spring-boot-base](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-base) | spring-boot 基础 | [spring boot 官方文档](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/)<br>[spring boot 中文官方文档](https://www.breakyizhan.com/springboot/3028.html) |
|
||||
| [spring-boot-yml-profile](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-yml-profile) | yml 语法和多配置切换 | [Using YAML Instead of Properties](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-external-config-yaml) |
|
||||
| [spring-boot-servlet](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-servlet) | 整合servlet 3.0 | [Embedded Servlet Container Support](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-embedded-container) |
|
||||
| [spring-boot-tomcat](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-tomcat) | spring-boot 整合外部容器(tomcat) | [Use Another Web Server](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#howto-use-another-web-server) |
|
||||
| [spring-boot-jsp](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-jsp) | spring-boot 整合 jsp | [JSP Limitations](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-jsp-limitations) |
|
||||
| [spring-boot-servlet](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-servlet) | 整合servlet 3.0 | [Embedded Servlet Container Support](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-embedded-container) |
|
||||
| [spring-boot-jsp](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-jsp) | spring-boot 内置容器整合 jsp | [JSP Limitations](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-jsp-limitations) |
|
||||
| [spring-boot-data-jpa](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-jsp) | spring-boot data jpa 的使用 | [Spring Data JPA](https://docs.spring.io/spring-data/jpa/docs/2.1.3.RELEASE/reference/html/) |
|
||||
| [spring-boot-mybatis](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-mybatis) | spring-boot 整合 mybatis<br/>boot 2.x 内置HikariDataSources数据源的配置 | [Mybatis-Spring](http://www.mybatis.org/spring/zh/index.html)<br/>[Mybatis-Spring-Boot-Autoconfigure](http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/) |
|
||||
| [spring-boot-druid-mybtais](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-druid-mybatis) | spring-boot 整合druid、mybatis | [Alibaba druid](https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)<br/>[druid-spring-boot-starter](https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter) |
|
||||
|
BIN
pictures/boot-dubbo-common.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
pictures/boot-dubbo-consumer1.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
pictures/boot-dubbo-provider.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
pictures/druid-status.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
pictures/rabbitmq-common.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
pictures/rabbitmq-consumer.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
pictures/rabbitmq-producer.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
pictures/spring-boot-base.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
pictures/spring-boot-data-jpa.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
pictures/spring-boot-dependencies.png
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
pictures/spring-boot-druid 控制台.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
pictures/spring-boot-druid-mybatis.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
pictures/spring-boot-dubbo.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
pictures/spring-boot-jsp.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
pictures/spring-boot-memcached.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
pictures/spring-boot-mongodb.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
pictures/spring-boot-mybatis.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
pictures/spring-boot-rabbitmq.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
pictures/spring-boot-redis.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
pictures/spring-boot-servlet.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
pictures/spring-boot-tomcat.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
pictures/spring-boot-websocket.png
Normal file
After Width: | Height: | Size: 17 KiB |
247
spring-boot/spring-boot-base/README.md
Normal file
@ -0,0 +1,247 @@
|
||||
# spring-boot 基础
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 项目结构说明
|
||||
|
||||
1. 本项目搭建一个简单的hello spring 的 web工程,简单说明spring-boot 的开箱即用的特性;
|
||||
2. 模板引擎采用freemaker 和 thymeleaf 作为示例,分别对应模板文件makershow.ftl 和 leafShow.html;
|
||||
3. spring boot 2.x 默认是不支持jsp的,需要额外的配置,关于使用jsp的整合可以参考[spring-boot-jsp](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-jsp)项目。
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目依赖
|
||||
|
||||
导入相关的starter(启动器)
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.1.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>spring-boot-base</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-boot-base</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!--模板引擎-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<!--web 启动器-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!--lombok 插件-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!--测试相关依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!--Spring Boot的Maven插件(Spring Boot Maven plugin)能够以Maven的方式为应用提供Spring Boot的支持-->
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
```
|
||||
|
||||
1. spring boot 项目默认继承自spring-boot-starter-parent,而spring-boot-starter-parent继承自spring-boot-dependencies, spring-boot-dependencies中定义了关于spring boot 依赖的各种jar包的版本,是spring boot 的版本管理中心。
|
||||
|
||||

|
||||
|
||||
2. 关于spring boot 2.x官方支持的所有starter 可以参见官方文档 [Table 13.1. Spring Boot application starters](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#using-boot-starter)
|
||||
|
||||
|
||||
|
||||
## 二、spring boot 主启动类
|
||||
|
||||
如果采用IDEA 或者 Spring Tool Suite (STS) 等开发工具创建的spring boot 工程,会默认创建启动类,如果没有创建,需要手动创建启动类
|
||||
|
||||
```java
|
||||
package com.heibaiying.springbootbase;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringBootBaseApplication {
|
||||
|
||||
// 启动类默认开启包扫描,扫描与主程序所在包及其子包,对于本工程而言 默认扫描 com.heibaiying.springbootbase
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringBootBaseApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@SpringBootApplication 注解是一个复合注解,里面包含了@ComponentScan注解,默认开启包扫描,扫描与主程序所在包及其子包,对于本工程而言 默认扫描 com.heibaiying.springbootbase
|
||||
|
||||
```java
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan(excludeFilters = {
|
||||
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
|
||||
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
|
||||
public @interface SpringBootApplication {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 三、开箱即用的web工程
|
||||
|
||||
在springbootBaseApplication.java 的同级目录创建controller文件夹,并在其中创建RestfulController.java,启动项目访问localhost:8080/restful/programmers 即可看到项目搭建成功。
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : restful 控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("restful")
|
||||
public class RestfulController {
|
||||
|
||||
@GetMapping("programmers")
|
||||
private List<Programmer> getProgrammers() {
|
||||
List<Programmer> programmers = new ArrayList<>();
|
||||
programmers.add(new Programmer("xiaoming", 12, 100000.00f, LocalDate.of(2019, Month.AUGUST, 2)));
|
||||
programmers.add(new Programmer("xiaohong", 23, 900000.00f, LocalDate.of(2013, Month.FEBRUARY, 2)));
|
||||
return programmers;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这里之所以能够开箱即用,是因为我们在项目中导入spring-boot-starter-web启动器,而@SpringBootApplication 复合注解中默认开启了@EnableAutoConfiguration注解允许开启自动化配置,spring在检查导入starter-web的依赖后就会开启web的自动化配置。
|
||||
|
||||
|
||||
|
||||
## 四、模板引擎
|
||||
|
||||
这里我们在一个项目中同时导入了freemaker 和 thymeleaf的starter(虽然并不推荐,但是在同一个项目中是可以混用这两种模板引擎的)。
|
||||
|
||||
#### 4.1 freemarker
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 跳转渲染模板引擎 默认模板的存放位置为classpath:templates
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("freemarker")
|
||||
public class FreeMarkerController {
|
||||
|
||||
@RequestMapping("show")
|
||||
private String programmerShow(ModelMap modelMap){
|
||||
List<Programmer> programmerList=new ArrayList<>();
|
||||
programmerList.add(new Programmer("xiaoming",12,100000.00f,LocalDate.of(2019,Month.AUGUST,2)));
|
||||
programmerList.add(new Programmer("xiaohong",23,900000.00f,LocalDate.of(2013,Month.FEBRUARY,2)));
|
||||
modelMap.addAttribute("programmers",programmerList);
|
||||
return "markerShow";
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>freemarker模板引擎</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<#list programmers as programmer>
|
||||
<li>姓名: ${programmer.name} 年龄: ${programmer.age}</li>
|
||||
</#list>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### 4.2 thymeleaf
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 跳转渲染模板引擎 默认模板的存放位置为classpath:templates
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("thymeleaf")
|
||||
public class ThymeleafController {
|
||||
|
||||
@RequestMapping("show")
|
||||
private String programmerShow(ModelMap modelMap) {
|
||||
List<Programmer> programmerList = new ArrayList<>();
|
||||
programmerList.add(new Programmer("xiaoming", 12, 100000.00f, LocalDate.of(2019, Month.AUGUST, 2)));
|
||||
programmerList.add(new Programmer("xiaohong", 23, 900000.00f, LocalDate.of(2013, Month.FEBRUARY, 2)));
|
||||
modelMap.addAttribute("programmers", programmerList);
|
||||
return "leafShow";
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>thymeleaf模板引擎</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul th:each="programmer:${programmers}">
|
||||
<li>
|
||||
姓名:<span th:text="${programmer.name}"></span>
|
||||
薪水:<span th:text="${programmer.salary}"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### 4.3 文档说明
|
||||
|
||||
freemarker:提供了完善的中文文档,地址 http://freemarker.foofun.cn/
|
||||
|
||||
thymeleaf:官方英文文档地址:[thymeleaf 3.0.11RELEASE](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.pdf)
|
||||
|
||||
注:我在本仓库中也上传了一份[thymeleaf中文文档(gangzi828(刘明刚 译)](https://github.com/heibaiying/spring-samples-for-all/tree/master/referenced%20documents),翻译的版本为3.0.5RELEASE
|
@ -47,6 +47,7 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!--Spring Boot的Maven插件(Spring Boot Maven plugin)能够以Maven的方式为应用提供Spring Boot的支持-->
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
@ -6,7 +6,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@SpringBootApplication
|
||||
public class SpringBootBaseApplication {
|
||||
|
||||
// 启动器默认开启包扫描,扫描与主程序所在包及其子包,对于本工程而言 默认扫描 com.heibaiying.springbootbase
|
||||
/*@SpringBootApplication 注解是一个复合注解,里面包含了@ComponentScan注解
|
||||
默认开启包扫描,扫描与主程序所在包及其子包,对于本工程而言 默认扫描 com.heibaiying.springbootbase*/
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringBootBaseApplication.class, args);
|
||||
}
|
||||
|
193
spring-boot/spring-boot-data-jpa/README.md
Normal file
@ -0,0 +1,193 @@
|
||||
# spring boot data jpa
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 项目结构
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目主要依赖
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<!-- data-jpa -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<!--引入mysql驱动-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.13</version>
|
||||
</dependency>
|
||||
<!--单元测试包-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
## 二、data jpa 的使用
|
||||
|
||||
#### 2.1 在application.yml 中配置数据源
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
#Hibernate默认创建的表是myisam引擎,可以用以下方式指定为使用innodb创建表
|
||||
database-platform: org.hibernate.dialect.MySQL57Dialect
|
||||
show-sql: true
|
||||
```
|
||||
|
||||
#### 2.2 新建查询接口
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 查询接口继承自CrudRepository,CrudRepository 默认定义了部分增删改查方法
|
||||
*/
|
||||
public interface ProgRepository extends CrudRepository<Programmer, Integer> {
|
||||
|
||||
/*
|
||||
* 方法名遵循命名规范的查询 更多命名规范可以参考官方文档所列出的这张表格
|
||||
*/
|
||||
List<Programmer> findAllByName(String name);
|
||||
|
||||
/*
|
||||
*分页排序查询
|
||||
*/
|
||||
Page<Programmer> findAll(Pageable pageable);
|
||||
|
||||
|
||||
/*
|
||||
* 占位符查询
|
||||
*/
|
||||
@Query(value = "select u from Programmer u where u.name = ?1 or u.salary = ?2")
|
||||
List<Programmer> findByConditionAndOrder(String name, float salary, Sort.Order order);
|
||||
|
||||
|
||||
/*
|
||||
* 传入参数名称
|
||||
*/
|
||||
@Query("select u from Programmer u where u.name = :name or u.age = :age")
|
||||
Programmer findByParam(@Param("name") String name,
|
||||
@Param("age") int age);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
关于查询方法遵循的命名规范和关键词见下表:
|
||||
|
||||
| Keyword | Sample | JPQL snippet |
|
||||
| ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| `And` | `findByLastnameAndFirstname` | `… where x.lastname = ?1 and x.firstname = ?2` |
|
||||
| `Or` | `findByLastnameOrFirstname` | `… where x.lastname = ?1 or x.firstname = ?2` |
|
||||
| `Is,Equals` | `findByFirstname`,`findByFirstnameIs`,<br>`findByFirstnameEquals` | `… where x.firstname = ?1` |
|
||||
| `Between` | `findByStartDateBetween` | `… where x.startDate between ?1 and ?2` |
|
||||
| `LessThan` | `findByAgeLessThan` | `… where x.age < ?1` |
|
||||
| `LessThanEqual` | `findByAgeLessThanEqual` | `… where x.age <= ?1` |
|
||||
| `GreaterThan` | `findByAgeGreaterThan` | `… where x.age > ?1` |
|
||||
| `GreaterThanEqual` | `findByAgeGreaterThanEqual` | `… where x.age >= ?1` |
|
||||
| `After` | `findByStartDateAfter` | `… where x.startDate > ?1` |
|
||||
| `Before` | `findByStartDateBefore` | `… where x.startDate < ?1` |
|
||||
| `IsNull` | `findByAgeIsNull` | `… where x.age is null` |
|
||||
| `IsNotNull,NotNull` | `findByAge(Is)NotNull` | `… where x.age not null` |
|
||||
| `Like` | `findByFirstnameLike` | `… where x.firstname like ?1` |
|
||||
| `NotLike` | `findByFirstnameNotLike` | `… where x.firstname not like ?1` |
|
||||
| `StartingWith` | `findByFirstnameStartingWith` | `… where x.firstname like ?1`(parameter bound with appended `%`) |
|
||||
| `EndingWith` | `findByFirstnameEndingWith` | `… where x.firstname like ?1`(parameter bound with prepended `%`) |
|
||||
| `Containing` | `findByFirstnameContaining` | `… where x.firstname like ?1`(parameter bound wrapped in `%`) |
|
||||
| `OrderBy` | `findByAgeOrderByLastnameDesc` | `… where x.age = ?1 order by x.lastname desc` |
|
||||
| `Not` | `findByLastnameNot` | `… where x.lastname <> ?1` |
|
||||
| `In` | `findByAgeIn(Collection<Age> ages)` | `… where x.age in ?1` |
|
||||
| `NotIn` | `findByAgeNotIn(Collection<Age> ages)` | `… where x.age not in ?1` |
|
||||
| `True` | `findByActiveTrue()` | `… where x.active = true` |
|
||||
| `False` | `findByActiveFalse()` | `… where x.active = false` |
|
||||
| `IgnoreCase` | `findByFirstnameIgnoreCase` | `… where UPPER(x.firstame) = UPPER(?1)` |
|
||||
|
||||
#### 2.3 测试类
|
||||
|
||||
```java
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class DataJPATests {
|
||||
|
||||
@Autowired
|
||||
private ProgRepository repository;
|
||||
|
||||
/**
|
||||
* 保存数据测试
|
||||
*/
|
||||
@Test
|
||||
public void save() {
|
||||
// 保存单条数据
|
||||
repository.save(new Programmer("pro01", 12, 2121.34f, new Date()));
|
||||
// 保存多条数据
|
||||
List<Programmer> programmers = new ArrayList<>();
|
||||
programmers.add(new Programmer("pro02", 22, 3221.34f, new Date()));
|
||||
programmers.add(new Programmer("pro03", 32, 3321.34f, new Date()));
|
||||
programmers.add(new Programmer("pro04", 44, 4561.34f, new Date()));
|
||||
programmers.add(new Programmer("pro01", 44, 4561.34f, new Date()));
|
||||
repository.saveAll(programmers);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询数据测试
|
||||
*/
|
||||
@Test
|
||||
public void get() {
|
||||
|
||||
// 遵循命名规范的查询
|
||||
List<Programmer> programmers = repository.findAllByName("pro01");
|
||||
programmers.forEach(System.out::println);
|
||||
|
||||
// 传入参数名称
|
||||
Programmer param = repository.findByParam("pro02", 22);
|
||||
System.out.println("findByParam:" + param);
|
||||
|
||||
// 占位符查询
|
||||
List<Programmer> byCondition = repository.findByConditionAndOrder("pro03", 3321.34f, Sort.Order.asc("salary"));
|
||||
System.out.println("byCondition:" + byCondition);
|
||||
|
||||
//条件与分页查询 需要注意的是这里的页数是从第0页开始计算的
|
||||
Page<Programmer> page = repository.findAll(PageRequest.of(0, 10, Sort.Direction.DESC, "salary"));
|
||||
page.get().forEach(System.out::println);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新数据测试
|
||||
*/
|
||||
@Test
|
||||
public void update() {
|
||||
// 保存主键相同的数据就认为是更新操作
|
||||
repository.save(new Programmer(1, "updatePro01", 12, 2121.34f, new Date()));
|
||||
Optional<Programmer> programmer = repository.findById(1);
|
||||
Assert.assertEquals(programmer.get().getName(), "updatePro01");
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除数据测试
|
||||
*/
|
||||
@Test
|
||||
public void delete() {
|
||||
Optional<Programmer> programmer = repository.findById(2);
|
||||
if (programmer.isPresent()) {
|
||||
repository.deleteById(2);
|
||||
}
|
||||
Assert.assertFalse(programmer.isPresent());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -1,6 +1,6 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/mysql?useUnicode=true&characterEncoding=utf-8
|
||||
url: jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
196
spring-boot/spring-boot-druid-mybatis/README.md
Normal file
@ -0,0 +1,196 @@
|
||||
# spring boot 整合 druid+mybatis
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 项目结构
|
||||
|
||||
1. 项目查询用的表对应的建表语句放置在resources的sql文件夹下;
|
||||
|
||||
2. 为了使用druid控制台的功能,项目以web的方式构建。
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目主要依赖
|
||||
|
||||
需要说明的是按照spring 官方对应自定义的starter 命名规范的推荐:
|
||||
|
||||
- 官方的starter命名:spring-boot-starter-XXXX
|
||||
- 其他第三方starter命名:XXXX-spring-boot-starte
|
||||
|
||||
所以mybatis的starter命名为mybatis-spring-boot-starter,如果有自定义starter需求,也需要按照此命名规则进行命名。
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<!--引入mysql驱动-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.13</version>
|
||||
</dependency>
|
||||
<!--druid 依赖-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>1.1.10</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
spring boot 与 mybatis 版本的对应关系:
|
||||
|
||||
| MyBatis-Spring-Boot-Starter | [MyBatis-Spring](http://www.mybatis.org/spring/index.html#Requirements) | Spring Boot |
|
||||
| --------------------------- | ------------------------------------------------------------ | ------------- |
|
||||
| **1.3.x (1.3.1)** | 1.3 or higher | 1.5 or higher |
|
||||
| **1.2.x (1.2.1)** | 1.3 or higher | 1.4 or higher |
|
||||
| **1.1.x (1.1.1)** | 1.3 or higher | 1.3 or higher |
|
||||
| **1.0.x (1.0.2)** | 1.2 or higher | 1.3 or higher |
|
||||
|
||||
|
||||
|
||||
## 二、整合 druid + mybatis
|
||||
|
||||
#### 2.1 在application.yml 中配置数据源
|
||||
|
||||
本用例采用druid作为数据库连接池,虽然druid性能略逊于Hikari,但是提供了更为全面的监控管理,可以按照实际需求选用druid或者Hikari。(关于Hikari数据源的配置可以参考[spring-boot-mbatis项目](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-mybatis))
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
# 使用 druid 作为连接池 更多配置的说明可以参见 druid starter 中文文档 https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
druid:
|
||||
# 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
|
||||
initialSize: 5
|
||||
# 最小连接池数量
|
||||
minIdle: 5
|
||||
# 最大连接池数量
|
||||
maxActive: 10
|
||||
# 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
|
||||
maxWait: 60000
|
||||
# Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
# 连接保持空闲而不被驱逐的最小时间
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
# 用来检测连接是否有效的sql 因数据库方言而差, 例如 oracle 应该写成 SELECT 1 FROM DUAL
|
||||
validationQuery: SELECT 1
|
||||
# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
|
||||
testWhileIdle: true
|
||||
# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
testOnBorrow: false
|
||||
# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
testOnReturn: false
|
||||
# 是否自动回收超时连接
|
||||
removeAbandoned: true
|
||||
# 超时时间(以秒数为单位)
|
||||
remove-abandoned-timeout: 180
|
||||
|
||||
# druid 监控的配置 如果不使用 druid 的监控功能的话 以下配置就不是必须的
|
||||
# 本项目监控台访问地址: http://localhost:8080/druid/login.html
|
||||
|
||||
# WebStatFilter用于采集web-jdbc关联监控的数据。
|
||||
# 更多配置可参见: https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_%E9%85%8D%E7%BD%AEWebStatFilter
|
||||
web-stat-filter:
|
||||
# 是否开启 WebStatFilter 默认是true
|
||||
enabled: true
|
||||
# 需要拦截的url
|
||||
url-pattern: /*
|
||||
# 排除静态资源的请求
|
||||
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
|
||||
|
||||
# Druid内置提供了一个StatViewServlet用于展示Druid的统计信息。
|
||||
# 更多配置可参见:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AE
|
||||
stat-view-servlet:
|
||||
#是否启用StatViewServlet 默认值true
|
||||
enabled: true
|
||||
# 需要拦截的url
|
||||
url-pattern: /druid/*
|
||||
# 允许清空统计数据
|
||||
reset-enable: true
|
||||
login-username: druid
|
||||
login-password: druid
|
||||
|
||||
|
||||
|
||||
# mybatis 相关配置
|
||||
mybatis:
|
||||
configuration:
|
||||
# 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。
|
||||
# oracle数据库建议配置为JdbcType.NULL, 默认是Other
|
||||
jdbc-type-for-null: 'null'
|
||||
# 是否打印sql语句 调试的时候可以开启
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
```
|
||||
|
||||
#### 2.2 新建查询接口和controller
|
||||
|
||||
```java
|
||||
@Mapper
|
||||
public interface ProgrammerDao {
|
||||
|
||||
|
||||
@Select("select * from programmer")
|
||||
List<Programmer> selectAll();
|
||||
|
||||
@Insert("insert into programmer (name, age, salary, birthday) VALUES (#{name}, #{age}, #{salary}, #{birthday})")
|
||||
void save(Programmer programmer);
|
||||
|
||||
@Select("select * from programmer where name = #{id}")
|
||||
Programmer selectById(int id);
|
||||
|
||||
@Update("update programmer set name=#{name},age=#{age},salary=#{salary},birthday=#{birthday} where id=#{id}")
|
||||
int modify(Programmer programmer);
|
||||
|
||||
@Delete(" delete from programmer where id = #{id}")
|
||||
void delete(int id);
|
||||
}
|
||||
```
|
||||
|
||||
```xml
|
||||
@RestController
|
||||
public class ProgrammerController {
|
||||
|
||||
@Autowired
|
||||
private ProgrammerDao programmerDao;
|
||||
|
||||
@GetMapping("/programmers")
|
||||
public List<Programmer> get() {
|
||||
return programmerDao.selectAll();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 关于druid监控数据的外部化调用
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description :在 Spring Boot 中可以通过 HTTP 接口将 Druid 监控数据以JSON 的形式暴露出去,
|
||||
* 实际使用中你可以根据你的需要自由地对监控数据、暴露方式进行扩展。
|
||||
*/
|
||||
|
||||
@RestController
|
||||
public class DruidStatController {
|
||||
|
||||
@GetMapping("/stat")
|
||||
public Object druidStat() {
|
||||
// DruidStatManagerFacade#getDataSourceStatDataList 该方法可以获取所有数据源的监控数据
|
||||
return DruidStatManagerFacade.getInstance().getDataSourceStatDataList();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
#### 2.4 druid 控制台的使用,默认访问地址 http://localhost:8080/druid/login.html
|
||||
|
||||

|
@ -1,71 +1,70 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/mysql?useUnicode=true&characterEncoding=utf-8
|
||||
url: jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
# 使用 druid 作为连接池 更多配置的说明可以参见 druid starter 中文文档 https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
|
||||
# 使用 druid 作为连接池 更多配置的说明可以参见 druid starter 中文文档 https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
druid:
|
||||
# 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
|
||||
# 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
|
||||
initialSize: 5
|
||||
# 最小连接池数量
|
||||
# 最小连接池数量
|
||||
minIdle: 5
|
||||
# 最大连接池数量
|
||||
# 最大连接池数量
|
||||
maxActive: 10
|
||||
# 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
|
||||
# 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
|
||||
maxWait: 60000
|
||||
# Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。
|
||||
# Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接。
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
# 连接保持空闲而不被驱逐的最小时间
|
||||
# 连接保持空闲而不被驱逐的最小时间
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
# 用来检测连接是否有效的sql 因数据库方言而差, 例如 oracle 应该写成 SELECT 1 FROM DUAL
|
||||
# 用来检测连接是否有效的sql 因数据库方言而差, 例如 oracle 应该写成 SELECT 1 FROM DUAL
|
||||
validationQuery: SELECT 1
|
||||
# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
|
||||
# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
|
||||
testWhileIdle: true
|
||||
# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
testOnBorrow: false
|
||||
# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
|
||||
testOnReturn: false
|
||||
# 是否自动回收超时连接
|
||||
# 是否自动回收超时连接
|
||||
removeAbandoned: true
|
||||
# 超时时间(以秒数为单位)
|
||||
# 超时时间(以秒数为单位)
|
||||
remove-abandoned-timeout: 180
|
||||
|
||||
# druid 监控的配置 如果不使用 druid 的监控功能的话 以下配置就不是必须的
|
||||
# 本项目监控台访问地址: http://localhost:8080/druid/login.html
|
||||
# druid 监控的配置 如果不使用 druid 的监控功能的话 以下配置就不是必须的
|
||||
# 本项目监控台访问地址: http://localhost:8080/druid/login.html
|
||||
|
||||
# WebStatFilter用于采集web-jdbc关联监控的数据。
|
||||
# 更多配置可参见: https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_%E9%85%8D%E7%BD%AEWebStatFilter
|
||||
# WebStatFilter用于采集web-jdbc关联监控的数据。
|
||||
# 更多配置可参见: https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_%E9%85%8D%E7%BD%AEWebStatFilter
|
||||
web-stat-filter:
|
||||
# 是否开启 WebStatFilter 默认是true
|
||||
# 是否开启 WebStatFilter 默认是true
|
||||
enabled: true
|
||||
# 需要拦截的url
|
||||
# 需要拦截的url
|
||||
url-pattern: /*
|
||||
# 排除静态资源的请求
|
||||
# 排除静态资源的请求
|
||||
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
|
||||
|
||||
# Druid内置提供了一个StatViewServlet用于展示Druid的统计信息。
|
||||
# 更多配置可参见:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AE
|
||||
# Druid内置提供了一个StatViewServlet用于展示Druid的统计信息。
|
||||
# 更多配置可参见:https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AE
|
||||
stat-view-servlet:
|
||||
#是否启用StatViewServlet 默认值true
|
||||
#是否启用StatViewServlet 默认值true
|
||||
enabled: true
|
||||
# 需要拦截的url
|
||||
# 需要拦截的url
|
||||
url-pattern: /druid/*
|
||||
# 允许清空统计数据
|
||||
# 允许清空统计数据
|
||||
reset-enable: true
|
||||
login-username: druid
|
||||
login-password: druid
|
||||
|
||||
|
||||
|
||||
# mybatis 相关配置
|
||||
# mybatis 相关配置
|
||||
mybatis:
|
||||
configuration:
|
||||
# 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。
|
||||
# oracle数据库建议配置为JdbcType.NULL, 默认是Other
|
||||
# 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。
|
||||
# oracle数据库建议配置为JdbcType.NULL, 默认是Other
|
||||
jdbc-type-for-null: 'null'
|
||||
# 是否打印sql语句 调试的时候可以开启
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
# 是否打印sql语句 调试的时候可以开启
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
348
spring-boot/spring-boot-dubbo/README.md
Normal file
@ -0,0 +1,348 @@
|
||||
# spring boot 整合 dubbo
|
||||
|
||||
## 一、 项目结构说明
|
||||
|
||||
1.1 按照dubbo 文档推荐的服务最佳实践,建议将服务接口、服务模型、服务异常等均放在 API 包中,所以项目采用maven多模块的构建方式,在spring-boot-dubbo下构建三个子模块:
|
||||
|
||||
1. boot-dubbo-common 是公共模块,用于存放公共的接口和bean,被boot-dubbo-provider和boot-dubbo-consumer在pom.xml中引用;
|
||||
2. boot-dubbo-provider 是服务的提供者,提供商品的查询服务;
|
||||
3. boot-dubbo-consumer是服务的消费者,调用provider提供的查询服务。
|
||||
|
||||
1.2 本项目dubbo的搭建采用zookeeper作为注册中心, 关于zookeeper的安装和基本操作可以参见我的手记 [Zookeeper 基础命令与Java客户端](https://github.com/heibaiying/LearningNotes/blob/master/notes/%E4%B8%AD%E9%97%B4%E4%BB%B6/ZooKeeper/ZooKeeper%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA%E4%B8%8EJava%E5%AE%A2%E6%88%B7%E7%AB%AF.md)
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 二、关键依赖
|
||||
|
||||
在父工程的项目中统一导入依赖dubbo的starter,父工程的pom.xml如下
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>boot-dubbo-common</module>
|
||||
<module>boot-dubbo-consumer</module>
|
||||
<module>boot-dubbo-provider</module>
|
||||
</modules>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.1.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>spring-boot-dubbo</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-boot-dubbo</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--引入dubbo start依赖-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.boot</groupId>
|
||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
||||
<version>0.2.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 三、公共模块(boot-dubbo-common)
|
||||
|
||||
- api 下为公共的调用接口;
|
||||
- bean 下为公共的实体类。
|
||||
|
||||

|
||||
|
||||
## 四、 服务提供者(boot-dubbo-provider)
|
||||
|
||||

|
||||
|
||||
#### 4.1 提供方配置
|
||||
|
||||
```yaml
|
||||
dubbo:
|
||||
application:
|
||||
name: boot-duboo-provider
|
||||
# 指定注册协议和注册地址 dubbo推荐使用zookeeper作为注册中心,并且在start依赖中引入了zookeeper的java客户端Curator
|
||||
registry:
|
||||
protocol: zookeeper
|
||||
address: 127.0.0.1:2181
|
||||
protocol.name: dubbo
|
||||
```
|
||||
|
||||
#### 4.2 使用注解@Service暴露服务
|
||||
|
||||
需要注意的是这里的@Service注解不是spring的注解,而是dubbo的注解 com.alibaba.dubbo.config.annotation.Service
|
||||
|
||||
```java
|
||||
package com.heibaiying.dubboprovider.service;
|
||||
|
||||
import com.alibaba.dubbo.config.annotation.Service;
|
||||
import com.heibaiying.api.IProductService;
|
||||
import com.heibaiying.bean.Product;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 产品提供接口实现类
|
||||
*/
|
||||
@Service(timeout = 5000)
|
||||
public class ProductService implements IProductService {
|
||||
|
||||
private static List<Product> productList = new ArrayList<>();
|
||||
|
||||
static {
|
||||
for (int i = 0; i < 20; i++) {
|
||||
productList.add(new Product(i, "产品" + i, i / 2 == 0, new Date(), 66.66f * i));
|
||||
}
|
||||
}
|
||||
|
||||
public Product queryProductById(int id) {
|
||||
for (Product product : productList) {
|
||||
if (product.getId() == id) {
|
||||
return product;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public List<Product> queryAllProducts() {
|
||||
return productList;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## 五、服务消费者(boot-dubbo-consumer)
|
||||
|
||||

|
||||
|
||||
#### 1.消费方的配置
|
||||
|
||||
```yaml
|
||||
dubbo:
|
||||
application:
|
||||
name: boot-duboo-provider
|
||||
# 指定注册协议和注册地址 dubbo推荐使用zookeeper作为注册中心,并且在start依赖中引入了zookeeper的java客户端Curator
|
||||
registry:
|
||||
protocol: zookeeper
|
||||
address: 127.0.0.1:2181
|
||||
protocol.name: dubbo
|
||||
# 关闭所有服务的启动时检查 (没有提供者时报错)视实际情况设置
|
||||
consumer:
|
||||
check: false
|
||||
server:
|
||||
port: 8090
|
||||
```
|
||||
|
||||
#### 2.使用注解@Reference引用远程服务
|
||||
|
||||
```java
|
||||
package com.heibaiying.dubboconsumer.controller;
|
||||
|
||||
import com.alibaba.dubbo.config.annotation.Reference;
|
||||
import com.heibaiying.api.IProductService;
|
||||
import com.heibaiying.bean.Product;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("sell")
|
||||
public class SellController {
|
||||
|
||||
// dubbo远程引用注解
|
||||
@Reference
|
||||
private IProductService productService;
|
||||
|
||||
@RequestMapping
|
||||
public String productList(Model model) {
|
||||
List<Product> products = productService.queryAllProducts();
|
||||
model.addAttribute("products", products);
|
||||
return "products";
|
||||
}
|
||||
|
||||
@RequestMapping("product/{id}")
|
||||
public String productDetail(@PathVariable int id, Model model) {
|
||||
Product product = productService.queryProductById(id);
|
||||
model.addAttribute("product", product);
|
||||
return "product";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 六、项目构建的说明
|
||||
|
||||
因为在项目中,consumer和provider模块均依赖公共模块,所以在构建consumer和provider项目前需要将common 模块安装到本地仓库,**依次**对**父工程**和**common模块**执行:
|
||||
|
||||
```shell
|
||||
mvn install -Dmaven.test.skip = true
|
||||
```
|
||||
|
||||
consumer中 pom.xml如下
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>spring-boot-dubbo</artifactId>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>boot-dubbo-consumer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>boot-dubbo-consumer</name>
|
||||
<description>dubbo project for Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<!--引入对公共模块的依赖-->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>boot-dubbo-common</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
```
|
||||
|
||||
provider中 pom.xml如下
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>spring-boot-dubbo</artifactId>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
|
||||
<artifactId>boot-dubbo-provider</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>boot-dubbo-provider</name>
|
||||
<description>dubbo project for Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<!--引入对公共模块的依赖-->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>boot-dubbo-common</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
```
|
||||
|
||||
## 七、关于dubbo新版本管理控制台的安装说明
|
||||
|
||||
安装:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/apache/incubator-dubbo-ops.git /var/tmp/dubbo-ops
|
||||
cd /var/tmp/dubbo-ops
|
||||
mvn clean package
|
||||
```
|
||||
|
||||
配置:
|
||||
|
||||
```sh
|
||||
配置文件为:
|
||||
dubbo-admin-backend/src/main/resources/application.properties
|
||||
主要的配置有 默认的配置就是127.0.0.1:2181:
|
||||
dubbo.registry.address=zookeeper://127.0.0.1:2181
|
||||
```
|
||||
|
||||
启动:
|
||||
|
||||
```sh
|
||||
mvn --projects dubbo-admin-backend spring-boot:run
|
||||
```
|
||||
|
||||
访问:
|
||||
|
||||
```
|
||||
http://127.0.0.1:8080
|
||||
```
|
@ -1,14 +1,13 @@
|
||||
dubbo:
|
||||
application:
|
||||
name: boot-duboo-provider
|
||||
# 指定注册协议和注册地址 dubbo推荐使用zookeeper作为注册中心,并且在start依赖中引入了zookeeper的java客户端Curator
|
||||
# 指定注册协议和注册地址 dubbo推荐使用zookeeper作为注册中心,并且在start依赖中引入了zookeeper的java客户端Curator
|
||||
registry:
|
||||
protocol: zookeeper
|
||||
address: 127.0.0.1:2181
|
||||
protocol.name: dubbo
|
||||
# 关闭所有服务的启动时检查 (没有提供者时报错)视实际情况设置
|
||||
# 关闭所有服务的启动时检查 (没有提供者时报错)视实际情况设置
|
||||
consumer:
|
||||
check: false
|
||||
server:
|
||||
port: 8090
|
||||
|
||||
port: 8090
|
@ -1,8 +1,8 @@
|
||||
dubbo:
|
||||
application:
|
||||
name: boot-duboo-provider
|
||||
# 指定注册协议和注册地址 dubbo推荐使用zookeeper作为注册中心,并且在start依赖中引入了zookeeper的java客户端Curator
|
||||
# 指定注册协议和注册地址 dubbo推荐使用zookeeper作为注册中心,并且在start依赖中引入了zookeeper的java客户端Curator
|
||||
registry:
|
||||
protocol: zookeeper
|
||||
address: 127.0.0.1:2181
|
||||
protocol.name: dubbo
|
||||
protocol.name: dubbo
|
84
spring-boot/spring-boot-jsp/README.md
Normal file
@ -0,0 +1,84 @@
|
||||
# spring boot 内置容器 整合 jsp
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 项目结构
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目主要依赖
|
||||
|
||||
```xml
|
||||
<!--整合 jsp 依赖包-->
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-jasper</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!--jsp jstl 标签支持-->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## 二、整合 jsp
|
||||
|
||||
#### 2.1 导入整合的依赖
|
||||
|
||||
```xml
|
||||
<!--整合 jsp 依赖包-->
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-jasper</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!--jsp jstl 标签支持-->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
#### 2.2 在application.yml 中指定访问视图文件的前缀和后缀
|
||||
|
||||
```yml
|
||||
spring:
|
||||
mvc:
|
||||
view:
|
||||
prefix: /WEB-INF/jsp/
|
||||
suffix: .jsp
|
||||
```
|
||||
|
||||
#### 2.3 新建controller和show.jsp 测试整合是否成功
|
||||
|
||||
```java
|
||||
@Controller
|
||||
@RequestMapping("index")
|
||||
public class JspController {
|
||||
|
||||
@RequestMapping
|
||||
public String jsp(Model model){
|
||||
Programmer programmer = new Programmer("heibai", 21, 1298.31f, LocalDate.now());
|
||||
model.addAttribute("programmer",programmer);
|
||||
return "show";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```jsp
|
||||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>programmer</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/show.css">
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li>姓名: ${programmer.name}</li>
|
||||
<li>年龄: ${programmer.age}</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
@ -40,6 +40,7 @@
|
||||
<artifactId>tomcat-embed-jasper</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!--jsp jstl 标签支持-->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
|
148
spring-boot/spring-boot-memcached/README.md
Normal file
@ -0,0 +1,148 @@
|
||||
# spring boot 整合 mecached
|
||||
|
||||
## 一、说明
|
||||
|
||||
### 1.1 XMemcached客户端说明
|
||||
|
||||
spring boot 官方并没有提供关于 memcached 的starter,所以我们这里还是采用XMemcached作为客户端进行整合。 XMemcached是基于java nio的memcached高性能客户端,支持完整的memcached协议,支持客户端分布并且提供了一致性哈希(consistent hash)算法的实现。
|
||||
|
||||
### 1.2 项目结构说明
|
||||
|
||||
memcached的整合配置位于config文件夹下。
|
||||
|
||||

|
||||
|
||||
### 1.3 主要依赖
|
||||
|
||||
```xml
|
||||
<!--memcached java 客户端-->
|
||||
<dependency>
|
||||
<groupId>com.googlecode.xmemcached</groupId>
|
||||
<artifactId>xmemcached</artifactId>
|
||||
<version>2.4.5</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 二、spring boot 整合 memcached
|
||||
|
||||
#### 2.1 单机配置
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public MemcachedClient memcachedClient() {
|
||||
XMemcachedClientBuilder builder = new XMemcachedClientBuilder("192.168.200.201:11211");
|
||||
MemcachedClient memcachedClient = null;
|
||||
try {
|
||||
memcachedClient = builder.build();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return memcachedClient;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 集群配置
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public MemcachedClient memcachedClientForCluster() {
|
||||
|
||||
List<InetSocketAddress> addressList = new ArrayList<InetSocketAddress>();
|
||||
addressList.add(new InetSocketAddress("192.168.200.201", 11211));
|
||||
addressList.add(new InetSocketAddress("192.168.200.201", 11212));
|
||||
// 赋予权重
|
||||
int[] weights = {1, 2};
|
||||
XMemcachedClientBuilder builder = new XMemcachedClientBuilder(addressList, weights);
|
||||
// 设置连接池大小
|
||||
builder.setConnectionPoolSize(10);
|
||||
// 协议工厂
|
||||
builder.setCommandFactory(new TextCommandFactory());
|
||||
// 分布策略,一致性哈希KetamaMemcachedSessionLocator或者ArraySessionLocator(默认)
|
||||
builder.setSessionLocator(new KetamaMemcachedSessionLocator());
|
||||
// 设置序列化器
|
||||
builder.setTranscoder(new SerializingTranscoder());
|
||||
MemcachedClient memcachedClient = null;
|
||||
try {
|
||||
memcachedClient = builder.build();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return memcachedClient;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 存储基本类型测试用例
|
||||
|
||||
xmemcached单机版本和集群版本注入的实例是相同的。
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : Memcached 操作基本对象
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class MemSamples {
|
||||
|
||||
@Autowired
|
||||
private MemcachedClient memcachedClient;
|
||||
|
||||
@Test
|
||||
public void operate() throws InterruptedException, MemcachedException, TimeoutException {
|
||||
memcachedClient.set("hello", 0, "Hello,cluster xmemcached");
|
||||
String value = memcachedClient.get("hello");
|
||||
System.out.println("hello=" + value);
|
||||
memcachedClient.delete("hello");
|
||||
value = memcachedClient.get("hello");
|
||||
System.out.println("hello=" + value);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.5 存储实体对象测试用例
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description :Memcached 序列化与反序列化
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class MemObjectSamples {
|
||||
|
||||
@Autowired
|
||||
private MemcachedClient memcachedClient;
|
||||
|
||||
@Test
|
||||
public void operate() throws InterruptedException, MemcachedException, TimeoutException {
|
||||
memcachedClient.set("programmer", 0, new Programmer("xiaoming", 12, 5000.21f, new Date()));
|
||||
Programmer programmer = memcachedClient.get("programmer");
|
||||
System.out.println("hello ," + programmer.getName());
|
||||
memcachedClient.delete("programmer");
|
||||
programmer = memcachedClient.get("programmer");
|
||||
Assert.assertNull(programmer);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 附:memcached 基本命令
|
||||
|
||||
| 命令 | 格式 | 说明 |
|
||||
| --------------- | -------------------------------------------------- | ------------------------------------- |
|
||||
| 新增 set | set key flags exTime length -> value | 无论什么情况,都可以插入 |
|
||||
| 新增 add | add key flags exTime length -> value | 只有当key不存在的情况下,才可以插入 |
|
||||
| 替换 replace | replace key flags exTime length -> value | 只修改已存在key的value值 |
|
||||
| 追加内容append | append key flags exTime length -> value | length表示追加的长度而不是总长度 |
|
||||
| 前面追加prepend | prepend key flags exTime length -> value | length表示追加的长度而不是总长度 |
|
||||
| 查询操作 get | get key | |
|
||||
| 检查更新 cas | cas key flags exTime length version -> value | 版本正确才更新 |
|
||||
| 详细获取 gets | gets key | 返回的最后一个数代表 key 的 CAS 令牌 |
|
||||
| 删除 delete | delete key | 将数据打一个删除标记 |
|
||||
| 自增 incr | incr key 增加偏移量 | incr和decr只能操作能转换为数字的Value |
|
||||
| 自减 decr | decr key 减少偏移量 | desr不能将数字减少至0以下 |
|
||||
| 清库 | flush_all | |
|
@ -35,7 +35,7 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!--memcached java 客户端-->
|
||||
<!--spring boot 并没有 memcached starter,所以对于memcached的整合是和在spring下整合方式是一样的-->
|
||||
<!--spring boot 并没有官方 memcached starter,所以对于memcached的整合是和在spring下整合方式是一样的-->
|
||||
<dependency>
|
||||
<groupId>com.googlecode.xmemcached</groupId>
|
||||
<artifactId>xmemcached</artifactId>
|
||||
|
182
spring-boot/spring-boot-mongodb/README.md
Normal file
@ -0,0 +1,182 @@
|
||||
# spring boot 整合 mongodb
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 用例结构
|
||||
|
||||
1. 本用例提供mongdb的简单整合用例;
|
||||
2. 提供用MongoTemplate的方式操作mongdb,见测试用例MongoOriginalTests.java
|
||||
3. 提供基于spring data jpa 的方式操作mongodb(推荐),见测试用例MongoJPATests.java
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目主要依赖
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 二、整合 mongodb
|
||||
|
||||
#### 2.1 在application.yml 中配置mongodb数据源
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
data:
|
||||
mongodb:
|
||||
database: spring
|
||||
uri: mongodb://192.168.0.108:27017
|
||||
```
|
||||
|
||||
#### 2.2 基于MongoTemplate实现对mongodb的操作
|
||||
|
||||
```java
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class MongoOriginalTests {
|
||||
|
||||
@Autowired
|
||||
private MongoTemplate mongoTemplate;
|
||||
|
||||
@Test
|
||||
public void insert() {
|
||||
// 单条插入
|
||||
mongoTemplate.insert(new Programmer("xiaoming", 12, 5000.21f, new Date()));
|
||||
List<Programmer> programmers = new ArrayList<Programmer>();
|
||||
// 批量插入
|
||||
programmers.add(new Programmer("xiaohong", 21, 52200.21f, new Date()));
|
||||
programmers.add(new Programmer("xiaolan", 34, 500.21f, new Date()));
|
||||
mongoTemplate.insert(programmers, Programmer.class);
|
||||
}
|
||||
|
||||
// 条件查询
|
||||
@Test
|
||||
public void select() {
|
||||
Criteria criteria = new Criteria();
|
||||
criteria.andOperator(where("name").is("xiaohong"), where("age").is(21));
|
||||
Query query = new Query(criteria);
|
||||
Programmer one = mongoTemplate.findOne(query, Programmer.class);
|
||||
System.out.println(one);
|
||||
}
|
||||
|
||||
|
||||
// 更新数据
|
||||
@Test
|
||||
public void MUpdate() {
|
||||
UpdateResult updateResult = mongoTemplate.updateMulti(query(where("name").is("xiaoming")), update("age", 35), Programmer.class);
|
||||
System.out.println("更新记录数:" + updateResult.getModifiedCount());
|
||||
}
|
||||
|
||||
// 删除指定数据
|
||||
@Test
|
||||
public void delete() {
|
||||
DeleteResult result = mongoTemplate.remove(query(where("name").is("xiaolan")), Programmer.class);
|
||||
System.out.println("影响记录数:" + result.getDeletedCount());
|
||||
System.out.println("是否成功:" + result.wasAcknowledged());
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 使用 data jpa 方式操作mongodb (推荐使用)
|
||||
|
||||
1.新建查询结构,查询方法按照支持的关键字命名
|
||||
|
||||
```java
|
||||
public interface ProgrammerRepository extends MongoRepository<Programmer, String> {
|
||||
|
||||
void deleteAllByName(String name);
|
||||
|
||||
Programmer findAllByName(String names);
|
||||
|
||||
Programmer findByNameAndAge(String name, int age);
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
2.测试
|
||||
|
||||
```java
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class MongoJPATests {
|
||||
|
||||
@Autowired
|
||||
private ProgrammerRepository repository;
|
||||
|
||||
@Test
|
||||
public void insert() {
|
||||
// 单条插入
|
||||
repository.save(new Programmer("python", 23, 21832.34f, new Date()));
|
||||
// 批量插入
|
||||
List<Programmer> programmers = new ArrayList<Programmer>();
|
||||
programmers.add(new Programmer("java", 21, 52200.21f, new Date()));
|
||||
programmers.add(new Programmer("Go", 34, 500.21f, new Date()));
|
||||
repository.saveAll(programmers);
|
||||
}
|
||||
|
||||
// 条件查询
|
||||
@Test
|
||||
public void select() {
|
||||
Programmer java = repository.findByNameAndAge("java", 21);
|
||||
Assert.assertEquals(java.getSalary(), 52200.21f, 0.01);
|
||||
}
|
||||
|
||||
|
||||
// 更新数据
|
||||
@Test
|
||||
public void MUpdate() {
|
||||
repository.save(new Programmer("Go", 8, 500.21f, new Date()));
|
||||
Programmer go = repository.findAllByName("Go");
|
||||
Assert.assertEquals(go.getAge(), 8);
|
||||
}
|
||||
|
||||
// 删除指定数据
|
||||
@Test
|
||||
public void delete() {
|
||||
repository.deleteAllByName("python");
|
||||
Optional<Programmer> python = repository.findById("python");
|
||||
Assert.assertFalse(python.isPresent());
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
查询方法支持的关键字如下,更多命名规范可以参见Spring Data MongoDB官方文档[Query Methods](https://docs.spring.io/spring-data/mongodb/docs/2.1.3.RELEASE/reference/html/#mongodb.repositories.queries):
|
||||
|
||||
| Keyword | Sample | Logical result |
|
||||
| ------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| `After` | `findByBirthdateAfter(Date date)` | `{"birthdate" : {"$gt" : date}}` |
|
||||
| `GreaterThan` | `findByAgeGreaterThan(int age)` | `{"age" : {"$gt" : age}}` |
|
||||
| `GreaterThanEqual` | `findByAgeGreaterThanEqual(int age)` | `{"age" : {"$gte" : age}}` |
|
||||
| `Before` | `findByBirthdateBefore(Date date)` | `{"birthdate" : {"$lt" : date}}` |
|
||||
| `LessThan` | `findByAgeLessThan(int age)` | `{"age" : {"$lt" : age}}` |
|
||||
| `LessThanEqual` | `findByAgeLessThanEqual(int age)` | `{"age" : {"$lte" : age}}` |
|
||||
| `Between` | `findByAgeBetween(int from, int to)` | `{"age" : {"$gt" : from, "$lt" : to}}` |
|
||||
| `In` | `findByAgeIn(Collection ages)` | `{"age" : {"$in" : [ages…]}}` |
|
||||
| `NotIn` | `findByAgeNotIn(Collection ages)` | `{"age" : {"$nin" : [ages…]}}` |
|
||||
| `IsNotNull`, `NotNull` | `findByFirstnameNotNull()` | `{"firstname" : {"$ne" : null}}` |
|
||||
| `IsNull`, `Null` | `findByFirstnameNull()` | `{"firstname" : null}` |
|
||||
| `Like`, `StartingWith`, `EndingWith` | `findByFirstnameLike(String name)` | `{"firstname" : name} (name as regex)` |
|
||||
| `NotLike`, `IsNotLike` | `findByFirstnameNotLike(String name)` | `{"firstname" : { "$not" : name }} (name as regex)` |
|
||||
| `Containing` on String | `findByFirstnameContaining(String name)` | `{"firstname" : name} (name as regex)` |
|
||||
| `NotContaining` on String | `findByFirstnameNotContaining(String name)` | `{"firstname" : { "$not" : name}} (name as regex)` |
|
||||
| `Containing` on Collection | `findByAddressesContaining(Address address)` | `{"addresses" : { "$in" : address}}` |
|
||||
| `NotContaining` on Collection | `findByAddressesNotContaining(Address address)` | `{"addresses" : { "$not" : { "$in" : address}}}` |
|
||||
| `Regex` | `findByFirstnameRegex(String firstname)` | `{"firstname" : {"$regex" : firstname }}` |
|
||||
| `(No keyword)` | `findByFirstname(String name)` | `{"firstname" : name}` |
|
||||
| `Not` | `findByFirstnameNot(String name)` | `{"firstname" : {"$ne" : name}}` |
|
||||
| `Near` | `findByLocationNear(Point point)` | `{"location" : {"$near" : [x,y]}}` |
|
||||
| `Near` | `findByLocationNear(Point point, Distance max)` | `{"location" : {"$near" : [x,y], "$maxDistance" : max}}` |
|
||||
| `Near` | `findByLocationNear(Point point, Distance min, Distance max)` | `{"location" : {"$near" : [x,y], "$minDistance" : min, "$maxDistance" : max}}` |
|
||||
| `Within` | `findByLocationWithin(Circle circle)` | `{"location" : {"$geoWithin" : {"$center" : [ [x, y], distance]}}}` |
|
||||
| `Within` | `findByLocationWithin(Box box)` | `{"location" : {"$geoWithin" : {"$box" : [ [x1, y1], x2, y2]}}}` |
|
||||
| `IsTrue`, `True` | `findByActiveIsTrue()` | `{"active" : true}` |
|
||||
| `IsFalse`, `False` | `findByActiveIsFalse()` | `{"active" : false}` |
|
||||
| `Exists` | `findByLocationExists(boolean exists)` | `{"location" : {"$exists" : exists }}` |
|
||||
|
249
spring-boot/spring-boot-mybatis/README.md
Normal file
@ -0,0 +1,249 @@
|
||||
# spring boot 整合 mybatis
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 项目结构
|
||||
|
||||
1. 项目查询用的表对应的建表语句放置在resources的sql文件夹下;
|
||||
|
||||
2. 关于mybatis sql的写法提供两种方式:
|
||||
|
||||
xml 写法:对应的类为ProgrammerMapper.java 和 programmerMapper.xml,用MybatisXmlTest进行测试;
|
||||
|
||||
注解写法:对应的类为Programmer.java ,用MybatisAnnotationTest进行测试。
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目主要依赖
|
||||
|
||||
需要说明的是按照spring 官方对应自定义的starter 命名规范的推荐:
|
||||
|
||||
- 官方的starter命名:spring-boot-starter-XXXX
|
||||
- 其他第三方starter命名:XXXX-spring-boot-starte
|
||||
|
||||
所以mybatis的starter命名为mybatis-spring-boot-starter,如果有自定义starter需求,也需要按照此命名规则进行命名。
|
||||
|
||||
```xml
|
||||
<!--spring 1.5 x 以上版本对应 mybatis 1.3.x (1.3.1)
|
||||
关于更多spring-boot 与 mybatis 的版本对应可以参见 <a href="http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/">-->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<!--引入mysql驱动-->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
spring boot 与 mybatis 版本的对应关系:
|
||||
|
||||
| MyBatis-Spring-Boot-Starter | [MyBatis-Spring](http://www.mybatis.org/spring/index.html#Requirements) | Spring Boot |
|
||||
| --------------------------- | ------------------------------------------------------------ | ------------- |
|
||||
| **1.3.x (1.3.1)** | 1.3 or higher | 1.5 or higher |
|
||||
| **1.2.x (1.2.1)** | 1.3 or higher | 1.4 or higher |
|
||||
| **1.1.x (1.1.1)** | 1.3 or higher | 1.3 or higher |
|
||||
| **1.0.x (1.0.2)** | 1.2 or higher | 1.3 or higher |
|
||||
|
||||
## 二、整合 mybatis
|
||||
|
||||
#### 2.1 在application.yml 中配置数据源
|
||||
|
||||
spring boot 2.x 版本默认采用Hikari作为数据库连接池,Hikari是目前java平台性能最好的连接池,性能好于druid。
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
# 如果不想配置对数据库连接池做特殊配置的话,以下关于连接池的配置就不是必须的
|
||||
# spring-boot 2 默认采用高性能的 Hikari 作为连接池 更多配置可以参考 https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
hikari:
|
||||
# 池中维护的最小空闲连接数
|
||||
minimum-idle: 10
|
||||
# 池中最大连接数,包括闲置和使用中的连接
|
||||
maximum-pool-size: 20
|
||||
# 此属性控制从池返回的连接的默认自动提交行为。默认为true
|
||||
auto-commit: true
|
||||
# 允许最长空闲时间
|
||||
idle-timeout: 30000
|
||||
# 此属性表示连接池的用户定义名称,主要显示在日志记录和JMX管理控制台中,以标识池和池配置。 默认值:自动生成
|
||||
pool-name: custom-hikari
|
||||
#此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
|
||||
max-lifetime: 1800000
|
||||
# 数据库连接超时时间,默认30秒,即30000
|
||||
connection-timeout: 30000
|
||||
# 连接测试sql 这个地方需要根据数据库方言差异而配置 例如 oracle 就应该写成 select 1 from dual
|
||||
connection-test-query: SELECT 1
|
||||
|
||||
# mybatis 相关配置
|
||||
mybatis:
|
||||
# 指定 sql xml 文件的位置
|
||||
mapper-locations: classpath*:mappers/*.xml
|
||||
configuration:
|
||||
# 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。
|
||||
# oracle数据库建议配置为JdbcType.NULL, 默认是Other
|
||||
jdbc-type-for-null: 'null'
|
||||
# 是否打印sql语句 调试的时候可以开启
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
```
|
||||
|
||||
#### 2.2 xml方式的sql语句
|
||||
|
||||
新建 ProgrammerMapper.java 和 programmerMapper.xml,及其测试类
|
||||
|
||||
```java
|
||||
@Mapper
|
||||
public interface ProgrammerMapper {
|
||||
|
||||
void save(Programmer programmer);
|
||||
|
||||
Programmer selectById(int id);
|
||||
|
||||
int modify(Programmer programmer);
|
||||
|
||||
void delete(int id);
|
||||
}
|
||||
```
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="com.heibaiying.springboot.dao.ProgrammerMapper">
|
||||
|
||||
<insert id="save">
|
||||
insert into programmer (name, age, salary, birthday) VALUES (#{name}, #{age}, #{salary}, #{birthday})
|
||||
</insert>
|
||||
|
||||
<select id="selectById" resultType="com.heibaiying.springboot.bean.Programmer">
|
||||
select * from programmer where name = #{id}
|
||||
</select>
|
||||
|
||||
<update id="modify">
|
||||
update programmer set name=#{name},age=#{age},salary=#{salary},birthday=#{birthday} where id=#{id}
|
||||
</update>
|
||||
|
||||
<delete id="delete">
|
||||
delete from programmer where id = #{id}
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
```
|
||||
|
||||
测试类
|
||||
|
||||
```java
|
||||
/***
|
||||
* @description: xml Sql测试类
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class MybatisXmlTest {
|
||||
|
||||
@Autowired
|
||||
private ProgrammerMapper mapper;
|
||||
|
||||
@Test
|
||||
public void save() {
|
||||
mapper.save(new Programmer("xiaominng", 12, 3467.34f, new Date()));
|
||||
mapper.save(new Programmer("xiaominng", 12, 3467.34f, new Date()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modify() {
|
||||
mapper.modify(new Programmer(1, "xiaohong", 112, 347.34f, new Date()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void selectByCondition() {
|
||||
Programmer programmers = mapper.selectById(1);
|
||||
System.out.println(programmers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete() {
|
||||
mapper.delete(2);
|
||||
Programmer programmers = mapper.selectById(2);
|
||||
Assert.assertNull(programmers);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 注解方式的sql语句
|
||||
|
||||
```java
|
||||
@Mapper
|
||||
public interface ProgrammerDao {
|
||||
|
||||
@Insert("insert into programmer (name, age, salary, birthday) VALUES (#{name}, #{age}, #{salary}, #{birthday})")
|
||||
void save(Programmer programmer);
|
||||
|
||||
@Select("select * from programmer where name = #{id}")
|
||||
Programmer selectById(int id);
|
||||
|
||||
@Update("update programmer set name=#{name},age=#{age},salary=#{salary},birthday=#{birthday} where id=#{id}")
|
||||
int modify(Programmer programmer);
|
||||
|
||||
@Delete(" delete from programmer where id = #{id}")
|
||||
void delete(int id);
|
||||
}
|
||||
```
|
||||
|
||||
测试类
|
||||
|
||||
```java
|
||||
/***
|
||||
* @description: 注解Sql测试类
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class MybatisAnnotationTest {
|
||||
|
||||
@Autowired
|
||||
private ProgrammerDao programmerDao;
|
||||
|
||||
@Test
|
||||
public void save() {
|
||||
programmerDao.save(new Programmer("xiaominng", 12, 3467.34f, new Date()));
|
||||
programmerDao.save(new Programmer("xiaominng", 12, 3467.34f, new Date()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void modify() {
|
||||
programmerDao.modify(new Programmer(1, "xiaolan", 21, 347.34f, new Date()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void selectByCondition() {
|
||||
Programmer programmers = programmerDao.selectById(1);
|
||||
System.out.println(programmers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delete() {
|
||||
programmerDao.delete(3);
|
||||
Programmer programmers = programmerDao.selectById(3);
|
||||
Assert.assertNull(programmers);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -3,8 +3,6 @@ package com.heibaiying.springboot.dao;
|
||||
import com.heibaiying.springboot.bean.Programmer;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : heibaiying
|
||||
*/
|
||||
|
@ -3,8 +3,6 @@ package com.heibaiying.springboot.dao;
|
||||
import com.heibaiying.springboot.bean.Programmer;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : heibaiying
|
||||
*/
|
||||
|
@ -1,55 +1,55 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/mysql?useUnicode=true&characterEncoding=utf-8
|
||||
url: jdbc:mysql://127.0.0.1:3306/mysql?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
|
||||
username: root
|
||||
password: root
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
||||
# 如果不想配置数据源的话,以下关于连接池的配置就不是必须的
|
||||
# spring-boot 2 默认采用高性能的 Hikari 作为连接池 更多配置可以参考 https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby
|
||||
# 如果不想配置对数据库连接池做特殊配置的话,以下关于连接池的配置就不是必须的
|
||||
# spring-boot 2 默认采用高性能的 Hikari 作为连接池 更多配置可以参考 https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
hikari:
|
||||
# 池中维护的最小空闲连接数
|
||||
# 池中维护的最小空闲连接数
|
||||
minimum-idle: 10
|
||||
# 池中最大连接数,包括闲置和使用中的连接
|
||||
# 池中最大连接数,包括闲置和使用中的连接
|
||||
maximum-pool-size: 20
|
||||
# 此属性控制从池返回的连接的默认自动提交行为。默认为true
|
||||
# 此属性控制从池返回的连接的默认自动提交行为。默认为true
|
||||
auto-commit: true
|
||||
# 允许最长空闲时间
|
||||
# 允许最长空闲时间
|
||||
idle-timeout: 30000
|
||||
# 此属性表示连接池的用户定义名称,主要显示在日志记录和JMX管理控制台中,以标识池和池配置。 默认值:自动生成
|
||||
# 此属性表示连接池的用户定义名称,主要显示在日志记录和JMX管理控制台中,以标识池和池配置。 默认值:自动生成
|
||||
pool-name: custom-hikari
|
||||
#此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
|
||||
#此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
|
||||
max-lifetime: 1800000
|
||||
# 数据库连接超时时间,默认30秒,即30000
|
||||
# 数据库连接超时时间,默认30秒,即30000
|
||||
connection-timeout: 30000
|
||||
# 连接测试sql 这个地方需要根据数据库方言差异而配置 例如 oracle 就应该写成 select 1 from dual
|
||||
# 连接测试sql 这个地方需要根据数据库方言差异而配置 例如 oracle 就应该写成 select 1 from dual
|
||||
connection-test-query: SELECT 1
|
||||
|
||||
# mybatis 相关配置
|
||||
# mybatis 相关配置
|
||||
mybatis:
|
||||
# 指定 sql xml 文件的位置
|
||||
# 指定 sql xml 文件的位置
|
||||
mapper-locations: classpath*:mappers/*.xml
|
||||
configuration:
|
||||
# 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。
|
||||
# oracle数据库建议配置为JdbcType.NULL, 默认是Other
|
||||
# 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。
|
||||
# oracle数据库建议配置为JdbcType.NULL, 默认是Other
|
||||
jdbc-type-for-null: 'null'
|
||||
# 是否打印sql语句 调试的时候可以开启
|
||||
# 是否打印sql语句 调试的时候可以开启
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
|
||||
# 注 1
|
||||
# 注 1
|
||||
# oracle
|
||||
# driver="oracle.jdbc.driver.OracleDriver"
|
||||
# url="jdbc:oracle:thin:@localhost:1521:数据库名"
|
||||
# url="jdbc:oracle:thin:@localhost:1521:数据库名"
|
||||
# mysql
|
||||
# driver="com.mysql.jdbc.Driver"
|
||||
# url="jdbc:mysql://localhost/数据库名?[后接参数]"
|
||||
# driver="com.mysql.cj.jdbc.Driver"
|
||||
# url="jdbc:mysql://localhost/数据库名?[后接参数]"
|
||||
|
||||
|
||||
# 注 2
|
||||
# mybatis 配置更多说明可以参考settings http://www.mybatis.org/mybatis-3/zh/configuration.html
|
||||
# 注 2
|
||||
# mybatis 配置更多说明可以参考settings http://www.mybatis.org/mybatis-3/zh/configuration.html
|
||||
|
||||
|
||||
# 注 3
|
||||
# spring boot 2.0 默认采用Hikari 作为连接池 github地址 https://github.com/brettwooldridge/HikariCP
|
||||
# 注 3
|
||||
# spring boot 2.0 默认采用Hikari 作为连接池 Hikari github地址 https://github.com/brettwooldridge/HikariCP
|
390
spring-boot/spring-boot-rabbitmq/README.md
Normal file
@ -0,0 +1,390 @@
|
||||
# spring boot 整合 rabbitmq
|
||||
|
||||
## 一、 项目结构说明
|
||||
|
||||
1.1 之前关于spring 整合 rabbitmq 我们采用的是单项目的方式,为了使得用例更具有实际意义,这里采用maven多模块的构建方式,在spring-boot-rabbitmq下构建三个子模块:
|
||||
|
||||
1. rabbitmq-common 是公共模块,用于存放公共的接口、配置和bean,被rabbitmq-producer和rabbitmq-consumer在pom.xml中引用;
|
||||
2. rabbitmq-producer 是消息的生产者模块;
|
||||
3. rabbitmq-consumer是消息的消费者模块。
|
||||
|
||||
1.2 关于rabbitmq安装、交换机、队列、死信队列等基本概念可以参考我的手记[《RabbitMQ实战指南》读书笔记](https://github.com/heibaiying/LearningNotes/blob/master/notes/%E4%B8%AD%E9%97%B4%E4%BB%B6/RabbitMQ/%E3%80%8ARabbitMQ%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97%E3%80%8B%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0.md),里面有详细的配图说明。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 二、关键依赖
|
||||
|
||||
在父工程的项目中统一导入依赖rabbitmq的starter(spring-boot-starter-amqp),父工程的pom.xml如下
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>rabbitmq-consumer</module>
|
||||
<module>rabbitmq-producer</module>
|
||||
<module>rabbitmq-common</module>
|
||||
</modules>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.1.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>spring-boot-rabbitmq</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-boot-rabbitmq</name>
|
||||
<description>RabbitMQ project for Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 三、公共模块(rabbitmq-common)
|
||||
|
||||
- bean 下为公共的实体类。
|
||||
- constant 下为公共配置,用静态常量引用。(这里我使用静态常量是为了方便引用,实际中也可以按照情况,抽取为公共配置文件)
|
||||
|
||||

|
||||
|
||||
```java
|
||||
package com.heibaiying.constant;
|
||||
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : rabbit 公用配置信息
|
||||
*/
|
||||
public class RabbitInfo {
|
||||
|
||||
// queue 配置
|
||||
public static final String QUEUE_NAME = "spring.boot.simple.queue";
|
||||
public static final String QUEUE_DURABLE = "true";
|
||||
|
||||
// exchange 配置
|
||||
public static final String EXCHANGE_NAME = "spring.boot.simple.exchange";
|
||||
public static final String EXCHANGE_TYPE = "topic";
|
||||
|
||||
// routing key
|
||||
public static final String ROUTING_KEY = "springboot.simple.*";
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 四、服务消费者(rabbitmq-consumer)
|
||||
|
||||

|
||||
|
||||
#### 4.1 消息消费者配置
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
rabbitmq:
|
||||
addresses: 127.0.0.1:5672
|
||||
# RabbitMQ 默认的用户名和密码都是guest 而虚拟主机名称是 "/"
|
||||
# 如果配置其他虚拟主机地址,需要预先用管控台或者图形界面创建 图形界面地址 http://主机地址:15672
|
||||
username: guest
|
||||
password: guest
|
||||
virtual-host: /
|
||||
listener:
|
||||
simple:
|
||||
# 为了保证信息能够被正确消费,建议签收模式设置为手工签收,并在代码中实现手工签收
|
||||
acknowledge-mode: manual
|
||||
# 侦听器调用者线程的最小数量
|
||||
concurrency: 10
|
||||
# 侦听器调用者线程的最大数量
|
||||
max-concurrency: 50
|
||||
```
|
||||
|
||||
#### 4.2 使用注解@RabbitListener和@RabbitHandler创建消息监听者
|
||||
|
||||
1. 使用注解创建的交换机、队列、和绑定关系会在项目初始化的时候自动创建,但是不会重复创建;
|
||||
2. 这里我们创建两个消息监听器,分别演示消息是基本类型和消息是对象时的配置区别。
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 消息是对象的消费者
|
||||
*/
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RabbitmqBeanConsumer {
|
||||
|
||||
@RabbitListener(bindings = @QueueBinding(
|
||||
value = @Queue(value = RabbitBeanInfo.QUEUE_NAME, durable = RabbitBeanInfo.QUEUE_DURABLE),
|
||||
exchange = @Exchange(value = RabbitBeanInfo.EXCHANGE_NAME, type = RabbitBeanInfo.EXCHANGE_TYPE),
|
||||
key = RabbitBeanInfo.ROUTING_KEY)
|
||||
)
|
||||
@RabbitHandler
|
||||
public void onMessage(@Payload Programmer programmer, @Headers Map<String, Object> headers, Channel channel) throws Exception {
|
||||
log.info("programmer:{} ", programmer);
|
||||
Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
|
||||
channel.basicAck(deliveryTag, false);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RabbitmqConsumer {
|
||||
|
||||
@RabbitListener(bindings = @QueueBinding(
|
||||
value = @Queue(value = RabbitInfo.QUEUE_NAME, durable = RabbitInfo.QUEUE_DURABLE),
|
||||
exchange = @Exchange(value = RabbitInfo.EXCHANGE_NAME, type = RabbitInfo.EXCHANGE_TYPE),
|
||||
key = RabbitInfo.ROUTING_KEY)
|
||||
)
|
||||
@RabbitHandler
|
||||
public void onMessage(Message message, Channel channel) throws Exception {
|
||||
MessageHeaders headers = message.getHeaders();
|
||||
// 获取消息头信息和消息体
|
||||
log.info("msgInfo:{} ; payload:{} ", headers.get("msgInfo"), message.getPayload());
|
||||
// DELIVERY_TAG 代表 RabbitMQ 向该Channel投递的这条消息的唯一标识ID,是一个单调递增的正整数
|
||||
Long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
|
||||
// 第二个参数代表是否一次签收多条,当该参数为 true 时,则可以一次性确认 DELIVERY_TAG 小于等于传入值的所有消息
|
||||
channel.basicAck(deliveryTag, false);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 五、 消息生产者(rabbitmq-producer)
|
||||
|
||||

|
||||
|
||||
#### 5.1 消息生产者配置
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
rabbitmq:
|
||||
addresses: 127.0.0.1:5672
|
||||
# RabbitMQ 默认的用户名和密码都是guest 而虚拟主机名称是 "/"
|
||||
# 如果配置其他虚拟主机地址,需要预先用管控台或者图形界面创建 图形界面地址 http://主机地址:15672
|
||||
username: guest
|
||||
password: guest
|
||||
virtual-host: /
|
||||
# 是否启用发布者确认 具体确认回调实现见代码
|
||||
publisher-confirms: true
|
||||
# 是否启用发布者返回 具体返回回调实现见代码
|
||||
publisher-returns: true
|
||||
# 是否启用强制消息 保证消息的有效监听
|
||||
template.mandatory: true
|
||||
|
||||
server:
|
||||
port: 8090
|
||||
```
|
||||
|
||||
#### 5.2 创建消息生产者
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 消息生产者
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RabbitmqProducer {
|
||||
|
||||
@Autowired
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
public void sendSimpleMessage(Map<String, Object> headers, Object message,
|
||||
String messageId, String exchangeName, String key) {
|
||||
// 自定义消息头
|
||||
MessageHeaders messageHeaders = new MessageHeaders(headers);
|
||||
// 创建消息
|
||||
Message<Object> msg = MessageBuilder.createMessage(message, messageHeaders);
|
||||
/* 确认的回调 确认消息是否到达 Broker 服务器 其实就是是否到达交换器
|
||||
如果发送时候指定的交换器不存在 ack就是false 代表消息不可达 */
|
||||
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
|
||||
log.info("correlationData:{} , ack:{}", correlationData.getId(), ack);
|
||||
if (!ack) {
|
||||
System.out.println("进行对应的消息补偿机制");
|
||||
}
|
||||
});
|
||||
/* 消息失败的回调
|
||||
* 例如消息已经到达交换器上,但路由键匹配任何绑定到该交换器的队列,会触发这个回调,此时 replyText: NO_ROUTE
|
||||
*/
|
||||
rabbitTemplate.setReturnCallback((message1, replyCode, replyText, exchange, routingKey) -> {
|
||||
log.info("message:{}; replyCode: {}; replyText: {} ; exchange:{} ; routingKey:{}",
|
||||
message1, replyCode, replyText, exchange, routingKey);
|
||||
});
|
||||
// 在实际中ID 应该是全局唯一 能够唯一标识消息 消息不可达的时候触发ConfirmCallback回调方法时可以获取该值,进行对应的错误处理
|
||||
CorrelationData correlationData = new CorrelationData(messageId);
|
||||
rabbitTemplate.convertAndSend(exchangeName, key, msg, correlationData);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 5.3 以单元测试的方式发送消息
|
||||
|
||||
```java
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class RabbitmqProducerTests {
|
||||
|
||||
@Autowired
|
||||
private RabbitmqProducer producer;
|
||||
|
||||
/***
|
||||
* 发送消息体为简单数据类型的消息
|
||||
*/
|
||||
@Test
|
||||
public void send() {
|
||||
Map<String, Object> heads = new HashMap<>();
|
||||
heads.put("msgInfo", "自定义消息头信息");
|
||||
// 模拟生成消息ID,在实际中应该是全局唯一的 消息不可达时候可以在setConfirmCallback回调中取得,可以进行对应的重发或错误处理
|
||||
String id = String.valueOf(Math.round(Math.random() * 10000));
|
||||
producer.sendSimpleMessage(heads, "hello Spring", id, RabbitInfo.EXCHANGE_NAME, "springboot.simple.abc");
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 发送消息体为bean的消息
|
||||
*/
|
||||
@Test
|
||||
public void sendBean() {
|
||||
String id = String.valueOf(Math.round(Math.random() * 10000));
|
||||
Programmer programmer = new Programmer("xiaoMing", 12, 12123.45f, new Date());
|
||||
producer.sendSimpleMessage(null, programmer, id, RabbitBeanInfo.EXCHANGE_NAME, RabbitBeanInfo.ROUTING_KEY);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 六、项目构建的说明
|
||||
|
||||
因为在项目中,consumer和producer模块均依赖公共模块,所以在构建consumer和producer项目前需要将common 模块安装到本地仓库,**依次**对**父工程**和**common模块**执行:
|
||||
|
||||
```shell
|
||||
mvn install -Dmaven.test.skip = true
|
||||
```
|
||||
|
||||
consumer中 pom.xml如下
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>spring-boot-rabbitmq</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>rabbitmq-consumer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>rabbitmq-consumer</name>
|
||||
<description>RabbitMQ consumer project for Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>rabbitmq-common</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
```
|
||||
|
||||
producer中 pom.xml如下
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>spring-boot-rabbitmq</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>rabbitmq-producer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>rabbitmq-producer</name>
|
||||
<description>RabbitMQ producer project for Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>rabbitmq-common</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
```
|
444
spring-boot/spring-boot-redis/README.md
Normal file
@ -0,0 +1,444 @@
|
||||
# spring boot 整合 redis
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 项目结构
|
||||
|
||||
1. RedisConfig.java实现了redisTemplate 序列化与反序列化的配置;
|
||||
2. RedisOperation和RedisObjectOperation分别封装了对基本类型和对象的操作。
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目主要依赖
|
||||
|
||||
```xml
|
||||
<!--redis starter -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<!--jackson 序列化包 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.9.8</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 二、整合 Redis
|
||||
|
||||
#### 2.1 在application.yml 中配置redis数据源
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
# 默认采用的也是 0 号数据库 redis官方在4.0之后版本就不推荐采用单节点多数据库(db1-db15)的方式存储数据,如果有需要应该采用集群方式构建
|
||||
database: 0
|
||||
|
||||
# 如果是集群节点 采用如下配置指定节点
|
||||
#spring.redis.cluster.nodes
|
||||
```
|
||||
|
||||
#### 2.2 封装redis基本操作
|
||||
|
||||
需要说明的是spring boot 提供了两个template 用于操作redis:
|
||||
|
||||
- StringRedisTemplate:由于redis在大多数使用情况下都是操作字符串类型的存储,所以spring boot 将对字符串的操作单独封装在StringRedisTemplate ;
|
||||
- RedisTemplate<Object, Object> :redis 用于操作任意类型的template。
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : redis 基本操作
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class RedisOperation {
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate redisTemplate;
|
||||
|
||||
/***
|
||||
* 操作普通字符串
|
||||
*/
|
||||
public void StringSet(String key, String value) {
|
||||
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
|
||||
valueOperations.set(key, value);
|
||||
}
|
||||
|
||||
/***
|
||||
* 操作列表
|
||||
*/
|
||||
public void ListSet(String key, List<String> values) {
|
||||
ListOperations<String, String> listOperations = redisTemplate.opsForList();
|
||||
values.forEach(value -> listOperations.leftPush(key, value));
|
||||
}
|
||||
|
||||
/***
|
||||
* 操作集合
|
||||
*/
|
||||
public void SetSet(String key, Set<String> values) {
|
||||
SetOperations<String, String> setOperations = redisTemplate.opsForSet();
|
||||
values.forEach(value -> setOperations.add(key, value));
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取字符串
|
||||
*/
|
||||
public String StringGet(String key) {
|
||||
ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
|
||||
return valueOperations.get(key);
|
||||
}
|
||||
|
||||
/***
|
||||
* 列表弹出元素
|
||||
*/
|
||||
public String ListLeftPop(String key) {
|
||||
ListOperations<String, String> listOperations = redisTemplate.opsForList();
|
||||
return listOperations.leftPop(key, 2, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/***
|
||||
* 集合弹出元素
|
||||
*/
|
||||
public String SetPop(String key) {
|
||||
SetOperations<String, String> setOperations = redisTemplate.opsForSet();
|
||||
return setOperations.pop(key);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : redis 基本操作
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class RedisObjectOperation {
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<Object, Object> objectRedisTemplate;
|
||||
|
||||
/***
|
||||
* 操作对象
|
||||
*/
|
||||
public void ObjectSet(Object key, Object value) {
|
||||
ValueOperations<Object, Object> valueOperations = objectRedisTemplate.opsForValue();
|
||||
valueOperations.set(key, value);
|
||||
}
|
||||
|
||||
/***
|
||||
* 操作元素为对象列表
|
||||
*/
|
||||
public void ListSet(Object key, List<Object> values) {
|
||||
ListOperations<Object, Object> listOperations = objectRedisTemplate.opsForList();
|
||||
values.forEach(value -> listOperations.leftPush(key, value));
|
||||
}
|
||||
|
||||
/***
|
||||
* 操作元素为对象集合
|
||||
*/
|
||||
public void SetSet(Object key, Set<Object> values) {
|
||||
SetOperations<Object, Object> setOperations = objectRedisTemplate.opsForSet();
|
||||
values.forEach(value -> setOperations.add(key, value));
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取对象
|
||||
*/
|
||||
public Object ObjectGet(Object key) {
|
||||
ValueOperations<Object, Object> valueOperations = objectRedisTemplate.opsForValue();
|
||||
return valueOperations.get(key);
|
||||
}
|
||||
|
||||
/***
|
||||
* 列表弹出元素
|
||||
*/
|
||||
public Object ListLeftPop(Object key) {
|
||||
ListOperations<Object, Object> listOperations = objectRedisTemplate.opsForList();
|
||||
return listOperations.leftPop(key, 2, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/***
|
||||
* 集合弹出元素
|
||||
*/
|
||||
public Object SetPop(Object key) {
|
||||
SetOperations<Object, Object> setOperations = objectRedisTemplate.opsForSet();
|
||||
return setOperations.pop(key);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 redisTemplate 序列化为json格式与反序列化
|
||||
|
||||
这里需要说明的spring boot 的 redisTemplate 本身是实现了对象的序列化与反序列化的,是支持直接存取对象的。但是这里的序列化默认采用的是JdkSerializationRedisSerializer.serialize()序列化为二进制码,这个本身是不影响redisTemplate 的操作的,因为redisTemplate在取出数据的时候会自动进行反序列化。
|
||||
|
||||
但是如果我们在命令行中使用get命令去获取数据时候,得到的是一串不直观的二进制码,所以我们尽量将其序列化为直观的json格式存储。
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 自定义序列化器
|
||||
* 不定义的话默认采用的是serializer.JdkSerializationRedisSerializer.serialize()序列化为二进制字节码 存储在数据库中不直观
|
||||
*/
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(redisConnectionFactory);
|
||||
|
||||
// 使用Jackson2JsonRedisSerialize 需要导入依赖 com.fasterxml.jackson.core jackson-databind
|
||||
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
// 第一个参数表示: 表示所有访问者都受到影响 包括 字段, getter / isGetter,setter,creator
|
||||
// 第二个参数表示: 所有类型的访问修饰符都是可接受的,不论是公有还有私有表变量都会被序列化
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
|
||||
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
|
||||
|
||||
// 设置key,value 序列化规则
|
||||
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.4 测试
|
||||
|
||||
```java
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class RedisTests {
|
||||
|
||||
@Autowired
|
||||
private RedisOperation redisOperation;
|
||||
|
||||
@Test
|
||||
public void StringOperation() {
|
||||
redisOperation.StringSet("hello", "redis");
|
||||
String s = redisOperation.StringGet("hello");
|
||||
Assert.assertEquals(s, "redis");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ListOperation() {
|
||||
redisOperation.ListSet("skill", Arrays.asList("java", "oracle", "vue"));
|
||||
String s = redisOperation.ListLeftPop("skill");
|
||||
Assert.assertEquals(s, "vue");
|
||||
}
|
||||
|
||||
/*
|
||||
* 需要注意的是Redis的集合(set)不仅不允许有重复元素,并且集合中的元素是无序的,
|
||||
* 不能通过索引下标获取元素。哪怕你在java中传入的集合是有序的newLinkedHashSet,但是实际在Redis存储的还是无序的集合
|
||||
*/
|
||||
@Test
|
||||
public void SetOperation() {
|
||||
redisOperation.SetSet("skillSet", Sets.newLinkedHashSet("java", "oracle", "vue"));
|
||||
String s = redisOperation.SetPop("skillSet");
|
||||
Assert.assertNotNull(s);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
<br/>
|
||||
|
||||
## 附:Redis的数据结构和操作命令
|
||||
|
||||
### 1.1 预备
|
||||
|
||||
#### 1.1.1 全局命令
|
||||
|
||||
1. 查看所有键: **keys \***
|
||||
|
||||
2. 查看键总数:**dbsize**
|
||||
|
||||
3. 检查键是否存在:**exists key**
|
||||
|
||||
4. 删除键:**del key [key ...]** 支持删除多个键
|
||||
|
||||
5. 键过期:**expire key seconds**
|
||||
|
||||
ttl命令会返回键的剩余过期时间, 它有3种返回值:
|
||||
|
||||
- 大于等于0的整数: 键剩余的过期时间。
|
||||
- -1: 键没设置过期时间。
|
||||
- -2: 键不存在
|
||||
|
||||
6. 键的数据结构 **type key**
|
||||
|
||||
#### 1.1.2 数据结构和内部编码
|
||||
|
||||
type命令实际返回的就是当前键的数据结构类型, 它们分别是:**string**(字符串) 、 **hash**(哈希) 、 **list**(列表) 、 **set**(集合) 、 **zset**(有序集合)
|
||||
|
||||
#### 1.1.3 单线程架构
|
||||
|
||||
1. 纯内存访问, Redis将所有数据放在内存中, 内存的响应时长大约为100纳秒, 这是Redis达到每秒万级别访问的重要基础。
|
||||
2. 非阻塞I/O, Redis使用epoll作为I/O多路复用技术的实现, 再加上Redis自身的事件处理模型将epoll中的连接、 读写、 关闭都转换为事件, 不在网络I/O上浪费过多的时间, 如图2-6所示。
|
||||
3. 单线程避免了线程切换和竞态产生的消耗。
|
||||
|
||||
### 1.2 字符串
|
||||
|
||||
| 作用 | 格式 | 参数或示例 |
|
||||
| ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| 设置值 | set key value \[ex seconds]\[px milliseconds][nx\|xx] setnx setex | ex seconds: 为键设置秒级过期时间。 <br/>px milliseconds: 为键设置毫秒级过期时间。<br/>nx: 键必须不存在, 才可以设置成功, 用于添加。<br/>xx: 与nx相反, 键必须存在, 才可以设置成功, 用于更新。 |
|
||||
| 获取值 | get key | r如果获取的键不存在 ,则返回nil(空) |
|
||||
| 批量设置 | mset key value [key value ...] | mset a 1 b 2 c 3 d 4 |
|
||||
| 批量获取值 | mget key [key ...] | mget a b c d |
|
||||
| 计数 | incr key decr key incrby key increment(指定数值自增)<br/>decrby key decrement(指定数值自减)<br/>incrbyfloat key increment (浮点数自增) | 值不是整数, 返回错误。 值是整数, 返回自增或自减后的结果。<br/>键不存在,创建键,并按照值为0自增或自减, 返回结果为1。 |
|
||||
| 追加值 | append key value | 向字符串的默认追加值 |
|
||||
| 字符串长度 | strlen key | 获取字符串长度,中文占用三个字节 |
|
||||
| 设置并返回原值 | getset key value | |
|
||||
| 设置指定位置的租字符串 | setrange key offeset value | |
|
||||
| 获取部分字符串 | getrange key start end | |
|
||||
|
||||
### 1.3 哈希
|
||||
|
||||
| 作用 | 格式 | 参数或示例 |
|
||||
| ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| 设置值 | hset key field value | hset user:1 name tom<br/>hset user:1 age 12 |
|
||||
| 获取值 | hget key field | hget user:1 name |
|
||||
| 删除field | hdel key field [field ...] | |
|
||||
| 计算field个数 | hlen key | |
|
||||
| 批量设置或获取field-value | hmget key field [field]<br/>hmset key field value [field value...] | hmset user:1 name mike age 12 city tianjin<br/>hmget user:1 name city |
|
||||
| 判断field是否存在 | hexists key field | |
|
||||
| 获取所有field | hkeys key | |
|
||||
| 获取所有value | hvals key | |
|
||||
| 获取所有的filed-value | hgetall key | 如果哈希元素个数比较多, 会存在阻塞Redis的可能。<br/>获取全部 可以使用hscan命令, 该命令会渐进式遍历哈希类型 |
|
||||
| 计数 | hincrby key field<br/>hincrbyfloat key field | |
|
||||
|
||||
### 1.4 列表
|
||||
|
||||
| 作用 | 格式 | 参数或示例 |
|
||||
| -------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| 增 | 左侧插入:lpush key value [value ...] 右侧插入:rpush key value [value ...] 某个指定元素前后插入:linsert key before\|after pivot value | |
|
||||
| 查 | 获取指定范围内的元素列表:lrange key start end 获取列表指定索引下标的元素:lindex key index 获取列表指定长度:llen key | lrange listkey 0 -1 |
|
||||
| 删 | 从列表左侧弹出元素:lpop key 从列表右侧弹出元素:rpop key 删除指定元素:lrem key count value 截取列表:ltrim key start end | count>0, 从左到右, 删除最多count个元素。<br/>count<0, 从右到左, 删除最多count绝对值个元素。<br/>count=0, 删除所有 |
|
||||
| 改 | 修改指定索引下标的元素:lset key index newValue | |
|
||||
| 阻塞操作 | blpop key [key ...] timeout brpop key [key ...] timeout | key[key...]: 多个列表的键。 timeout: 阻塞时间\|等待时间(单位: 秒) |
|
||||
|
||||
|
||||
|
||||
### 1.5 集合
|
||||
|
||||
集合(set) 类型也是用来保存多个的字符串元素, 但和列表类型不一样的是, **集合中不允许有重复元素**, 并且集合中的元素是无序的, **不能通过索引下标获取元素**。
|
||||
|
||||
**集合内操作**:
|
||||
|
||||
| 作用 | 格式 | 参数或示例 |
|
||||
| -------------------- | ------------------------------ | ----------------------------------------- |
|
||||
| 添加元素 | sadd key element [element ...] | 返回结果为添加成功的元素个数 |
|
||||
| 删除元素 | srem key element [element ...] | 返回结果为成功删除的元素个数 |
|
||||
| 计算元素个数 | scard key | |
|
||||
| 判断元素是否在集合中 | sismember key element | |
|
||||
| 随机返回 | srandmember key [count] | 随机从集合返回指定个数元素,count 默认为1 |
|
||||
| 从集合随机弹出元素 | spop key | srandmember 不会从集合中删除元素,spop 会 |
|
||||
| 获取集合中所有元素 | smembers key | 可用sscan 代替 |
|
||||
|
||||
**集合间操作**:
|
||||
|
||||
| 作用 | 格式 |
|
||||
| ---------------------------- | ------------------------------------------------------------ |
|
||||
| 求多个集合的交集 | sinter key [key ...] |
|
||||
| 求多个集合的并集 | suinon key [key ...] |
|
||||
| 求多个集合的差集 | sdiff key [key ...] |
|
||||
| 将交集、并集、差集的结果保存 | sinterstore destination key [key ...] <br/>suionstore destination key [key ...]<br/>sdiffstore destination key [key ...] |
|
||||
|
||||
### 1.6 有序集合
|
||||
|
||||
有序集合中的元素可以排序。 但是它和列表使用索引下标作为排序依据不同的是, 它给每个元素设置一个分数(score) 作为排序的依据。
|
||||
|
||||
**集合内操作**:
|
||||
|
||||
| 作用 | 格式 | 参数或示例 |
|
||||
| ------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| 添加成员 | zadd key score member [score member ...] | nx: member必须不存在, 才可设置成功, 用于添加。<br> xx: member必须存在, 才可以设置成功, 用于更新。<br/>ch: 返回此次操作后, 有序集合元素和分数发生变化的个数<br/>incr: 对score做增加, 相当于后面介绍的zincrby。 |
|
||||
| 计算成员个数 | zcard key | |
|
||||
| 计算某个成员的分数 | zscore key member | |
|
||||
| 计算某个成员的排名 | zrank key member zrevrank key member | zrank是从分数从低到高返回排名, zrevrank反之。 |
|
||||
| 删除成员 | zrem key member [member ...] | |
|
||||
| 增加成员分数 | zincrby key increment member | zincrby user:ranking 9 tom |
|
||||
| 返回指定排名范围的成员 | zrange key start end [withscores] zrange key start end [withscores] | zrange是从低到高返回, zrevrange反之。 |
|
||||
| 返回指定分数范围内的成员 | zrangebyscore key min max \[withscores][limit offset count] zrevrangebyscore key max min \[withscores][limit offset count] | 其中zrangebyscore按照分数从低到高返回, zrevrangebyscore反之。 [limit offset count]选项可以限制输出的起始位置和个数: 同时min和max还支持开区间(小括号) 和闭区间(中括号) , -inf和+inf分别代表无限小和无限大 |
|
||||
| 删除指定排名内的升序元素 | zremrangerank key start end | |
|
||||
| 删除指定分数范围的成员 | zremrangebyscore key min max | |
|
||||
|
||||
**集合间操作**:
|
||||
|
||||
| 作用 | 格式 |
|
||||
| ---- | ------------------------------------------------------------ |
|
||||
| 交集 | zinterstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] |
|
||||
| 并集 | zunionstore destination numkeys key \[key ...] [weights weight [weight ...]] \[aggregate sum\|min\|max] |
|
||||
|
||||
- destination: 交集计算结果保存到这个键。
|
||||
- numkeys: 需要做交集计算键的个数。
|
||||
- key[key...]: 需要做交集计算的键。
|
||||
- weights weight[weight...]: 每个键的权重, 在做交集计算时, 每个键中的每个member会将自己分数乘以这个权重, 每个键的权重默认是1。
|
||||
- aggregate sum|min|max: 计算成员交集后, 分值可以按照sum(和) 、min(最小值) 、 max(最大值) 做汇总, 默认值是sum。
|
||||
|
||||
### 1.7 键管理
|
||||
|
||||
#### 1.7.1 单个键管理
|
||||
|
||||
##### 1.键重命名
|
||||
|
||||
**rename key newkey**
|
||||
|
||||
为了防止被强行rename, Redis提供了renamenx命令, 确保只有newKey不存在时候才被覆盖。
|
||||
|
||||
##### 2. 随机返回键
|
||||
|
||||
**random key**
|
||||
|
||||
##### 3.键过期
|
||||
|
||||
- expire key seconds: 键在seconds秒后过期。
|
||||
- expireat key timestamp: 键在秒级时间戳timestamp后过期。
|
||||
- pexpire key milliseconds: 键在milliseconds毫秒后过期。
|
||||
- pexpireat key milliseconds-timestamp键在毫秒级时间戳timestamp后过期
|
||||
|
||||
注意:
|
||||
|
||||
1. 如果expire key的键不存在, 返回结果为0
|
||||
2. 如果设置过期时间为负值, 键会立即被删除, 犹如使用del命令一样
|
||||
3. persist key t命令可以将键的过期时间清除
|
||||
4. 对于字符串类型键, 执行set命令会去掉过期时间, 这个问题很容易在开发中被忽视
|
||||
5. Redis不支持二级数据结构(例如哈希、 列表) 内部元素的过期功能, 例如不能对列表类型的一个元素做过期时间设置
|
||||
6. setex命令作为set+expire的组合, 不但是原子执行, 同时减少了一次网络通讯的时间
|
||||
|
||||
#### 1.7.2 键遍历
|
||||
|
||||
##### 1. 全量键遍历
|
||||
|
||||
**keys pattern**
|
||||
|
||||
##### 2. 渐进式遍历
|
||||
|
||||
scan cursor \[match pattern] \[count number]
|
||||
|
||||
- cursor是必需参数, 实际上cursor是一个游标, 第一次遍历从0开始, 每次scan遍历完都会返回当前游标的值, 直到游标值为0, 表示遍历结束。
|
||||
- match pattern是可选参数, 它的作用的是做模式的匹配, 这点和keys的模式匹配很像。
|
||||
- count number是可选参数, 它的作用是表明每次要遍历的键个数, 默认值是10, 此参数可以适当增大。
|
||||
|
||||
#### 1.7.3 数据库管理
|
||||
|
||||
##### 1.切换数据库
|
||||
|
||||
**select dbIndex**
|
||||
|
||||
##### 2.flushdb/flushall
|
||||
|
||||
flushdb/flushall命令用于清除数据库, 两者的区别的是flushdb只清除当前数据库, flushall会清除所有数据库。
|
@ -2,8 +2,8 @@ spring:
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
# 默认采用的也是 0 号数据库 redis官方在4.0之后版本就不推荐采用单节点多数据库(db1-db15)的方式存储数据,如果有需要应该采用集群方式构建
|
||||
# 默认采用的也是 0 号数据库 redis官方在4.0之后版本就不推荐采用单节点多数据库(db1-db15)的方式存储数据,如果有需要应该采用集群方式构建
|
||||
database: 0
|
||||
|
||||
# 如果是集群节点 采用如下配置指定节点
|
||||
# 如果是集群节点 采用如下配置指定节点
|
||||
#spring.redis.cluster.nodes
|
@ -2,7 +2,6 @@ package com.heibaiying.springbootredis;
|
||||
|
||||
import com.heibaiying.springbootredis.bean.Programmer;
|
||||
import com.heibaiying.springbootredis.redis.RedisObjectOperation;
|
||||
import com.heibaiying.springbootredis.redis.RedisOperation;
|
||||
import org.assertj.core.util.Sets;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
@ -11,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
|
230
spring-boot/spring-boot-servlet/README.md
Normal file
@ -0,0 +1,230 @@
|
||||
# spring boot 整合 servlet
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 项目结构说明
|
||||
|
||||
1. 项目提供与servlet整合的两种方式,一种是servlet3.0 原生的注解方式,一种是采用spring 注册的方式;
|
||||
2. servlet、过滤器、监听器分别位于servlet、filter、listen 下,其中以Annotation命名结尾的代表是servlet注解方式实现,采用spring注册方式则在ServletConfig中进行注册;
|
||||
3. 为了说明外置容器对servlet注解的自动发现机制,项目采用外置容器构建,关于spring boot 整合外置容器的详细说明可以参考[spring-boot-tomcat](https://github.com/heibaiying/spring-samples-for-all/tree/master/spring-boot/spring-boot-tomcat)
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目依赖
|
||||
|
||||
```xml
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<!--排除依赖 使用外部tomcat容器启动-->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!--使用外置容器时候SpringBootServletInitializer 依赖此包 -->
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!--servlet api 注解依赖包-->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
## 二、采用spring 注册方式整合 servlet
|
||||
|
||||
#### 2.1 新建过滤器、监听器和servlet
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 自定义过滤器
|
||||
*/
|
||||
|
||||
public class CustomFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
request.setAttribute("filterParam","我是filter传递的参数");
|
||||
chain.doFilter(request,response);
|
||||
response.getWriter().append(" CustomFilter ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 自定义监听器
|
||||
*/
|
||||
public class CustomListen implements ServletContextListener {
|
||||
|
||||
//Web应用程序初始化过程正在启动的通知
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
System.out.println("容器初始化启动");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 通知servlet上下文即将关闭
|
||||
* 这个地方如果我们使用的是spring boot 内置的容器 是监听不到销毁过程,所以我们使用了外置 tomcat 容器
|
||||
*/
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
System.out.println("容器即将销毁");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 自定义servlet
|
||||
*/
|
||||
public class CustomServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
System.out.println("doGet 执行:" + req.getAttribute("filterParam"));
|
||||
resp.getWriter().append("CustomServlet");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
doGet(req, resp);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 注册过滤器、监听器和servlet
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
*/
|
||||
@Configuration
|
||||
public class ServletConfig {
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean registrationBean() {
|
||||
return new ServletRegistrationBean<HttpServlet>(new CustomServlet(), "/servlet");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean filterRegistrationBean() {
|
||||
FilterRegistrationBean bean = new FilterRegistrationBean<Filter>();
|
||||
bean.setFilter(new CustomFilter());
|
||||
bean.addUrlPatterns("/servlet");
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletListenerRegistrationBean listenerRegistrationBean() {
|
||||
return new ServletListenerRegistrationBean<ServletContextListener>(new CustomListen());
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## 三、采用注解方式整合 servlet
|
||||
|
||||
#### 3.1 新建过滤器、监听器和servlet,分别使用@WebFilter、@WebListener、@WebServlet注解标注
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 自定义过滤器
|
||||
*/
|
||||
|
||||
@WebFilter(urlPatterns = "/servletAnn")
|
||||
public class CustomFilterAnnotation implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
chain.doFilter(request,response);
|
||||
response.getWriter().append(" CustomFilter Annotation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description :自定义监听器
|
||||
*/
|
||||
@WebListener
|
||||
public class CustomListenAnnotation implements ServletContextListener {
|
||||
|
||||
//Web应用程序初始化过程正在启动的通知
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
System.out.println("容器初始化启动 Annotation");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 通知servlet上下文即将关闭
|
||||
* 这个地方如果我们使用的是spring boot 内置的容器 是监听不到销毁过程,所以我们使用了外置 tomcat 容器
|
||||
*/
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
System.out.println("容器即将销毁 Annotation");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 自定义servlet
|
||||
*/
|
||||
@WebServlet(urlPatterns = "/servletAnn")
|
||||
public class CustomServletAnnotation extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.getWriter().append("CustomServlet Annotation");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
doGet(req, resp);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 3.2 使注解生效
|
||||
|
||||
1. 如果是内置容器,需要在启动类上添加@ServletComponentScan("com.heibaiying.springbootservlet") ,指定扫描的包目录;
|
||||
2. 如果是外置容器,不需要进行任何配置,依靠容器内建的discovery机制自动发现,需要说明的是这里的容器必须支持servlet3.0(tomcat从7.0版本开始支持Servlet3.0)。
|
@ -37,17 +37,16 @@
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--servlet api 注解依赖包-->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -12,7 +12,7 @@ import java.io.IOException;
|
||||
* @description : 自定义servlet
|
||||
*/
|
||||
@WebServlet(urlPatterns = "/servletAnn")
|
||||
public class CustomServletAnnation extends HttpServlet {
|
||||
public class CustomServletAnnotation extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
101
spring-boot/spring-boot-tomcat/README.md
Normal file
@ -0,0 +1,101 @@
|
||||
# spring boot 整合 tomcat
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 项目结构说明
|
||||
|
||||
spring boot 整合 tomcat 后支持jsp 的使用(内置容器默认是不支持jsp),所以项目整合后采用jspController 跳转到show.jsp测试整合是否成功。
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目主要依赖
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<!--排除内置容器依赖 使用外部tomcat容器启动-->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!--使用外置容器时候SpringBootServletInitializer 依赖此包 -->
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## 二、整合 tomcat
|
||||
|
||||
#### 2.1 修改启动类,继承自SpringBootServletInitializer,并覆盖重写其中configure方法
|
||||
|
||||
```java
|
||||
/**
|
||||
* 如果用外置tomcat,启动报错java.lang.NoClassDefFoundError: javax/el/ELManager
|
||||
* 是因为tomcat 7.0 el-api包中没有ELManager类 , 切换tomcat 为8.0 以上版本即可
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class SpringBootTomcatApplication extends SpringBootServletInitializer {
|
||||
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
//传入SpringBoot应用的主程序
|
||||
return application.sources(SpringBootTomcatApplication.class);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringBootTomcatApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 在application.yml 中指定访问视图文件的前缀和后缀
|
||||
|
||||
```yml
|
||||
spring:
|
||||
mvc:
|
||||
view:
|
||||
prefix: /WEB-INF/jsp/
|
||||
suffix: .jsp
|
||||
```
|
||||
|
||||
#### 2.3 新建controller和show.jsp 测试整合是否成功
|
||||
|
||||
```java
|
||||
@Controller
|
||||
@RequestMapping("index")
|
||||
public class JspController {
|
||||
|
||||
@RequestMapping
|
||||
public String jsp(Model model){
|
||||
Programmer programmer = new Programmer("heibai", 21, 1298.31f, LocalDate.now());
|
||||
model.addAttribute("programmer",programmer);
|
||||
return "show";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```jsp
|
||||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>programmer</title>
|
||||
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/show.css">
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li>姓名: ${programmer.name}</li>
|
||||
<li>年龄: ${programmer.age}</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
183
spring-boot/spring-boot-websocket/README.md
Normal file
@ -0,0 +1,183 @@
|
||||
# spring boot websocket
|
||||
|
||||
## 一、说明
|
||||
|
||||
### 1.1 项目结构说明
|
||||
|
||||
1. 项目模拟一个简单的群聊功能,为区分不同的聊天客户端,登录时候将临时用户名存储在session当中;
|
||||
2. 关于websocket的主要配置在websocket文件夹下;
|
||||
3. 模板引擎采用freemaker;
|
||||
4. 项目以web的方式构建。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 1.2 主要依赖
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!--spring boot webSocket 的依赖包 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 二、spring boot websocket
|
||||
|
||||
#### 2.1 创建消息处理类ChatSocket,使用@ServerEndpoint声明websocket服务
|
||||
|
||||
```java
|
||||
@ServerEndpoint(value = "/socket/{username}")
|
||||
@Component
|
||||
public class ChatSocket {
|
||||
|
||||
/**
|
||||
* 建立连接时候触发
|
||||
*/
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("username") String username) {
|
||||
// 这个方法是线程不安全的
|
||||
Constant.nameAndSession.putIfAbsent(username, session);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 关闭连接时候触发
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose(Session session, @PathParam("username") String username) {
|
||||
Constant.nameAndSession.remove(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理消息
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(Session session, String message, @PathParam("username") String username) throws UnsupportedEncodingException {
|
||||
// 防止中文乱码
|
||||
String msg = URLDecoder.decode(message, "utf-8");
|
||||
// 简单模拟群发消息
|
||||
Constant.nameAndSession.forEach((s, webSocketSession)
|
||||
-> {
|
||||
try {
|
||||
webSocketSession.getBasicRemote().sendText(username + " : " + msg);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### 2.2 配置ServerEndpointExporter,ServerEndpointExporter会在运行时候自动注册我们用@ServerEndpoint声明的websocket服务。
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
public class WebSocketConfig {
|
||||
|
||||
/***
|
||||
* 检测{@link javax.websocket.server.ServerEndpointConfig}和{@link ServerEndpoint} 类型的bean,
|
||||
* 并在运行时使用标准Java WebSocket时注册。
|
||||
* 我们在{@link com.heibaiying.springboot.websocket.WebSocketConfig}中就是使用@ServerEndpoint去声明websocket服务
|
||||
*/
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 前端websocket的实现
|
||||
|
||||
```jsp
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>${Session["username"]}您好!欢迎进入群聊大厅!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h5>${Session["username"]}您好!欢迎进入群聊大厅!</h5>
|
||||
<input id="message" type="text">
|
||||
<button id="btn">发送消息</button>
|
||||
<div id="show">
|
||||
|
||||
</div>
|
||||
<script>
|
||||
let btn = document.getElementById("btn");
|
||||
let message = document.getElementById("message");
|
||||
let show = document.getElementById("show");
|
||||
let ws = new WebSocket("ws://localhost:8080/socket/${Session["username"]}");
|
||||
ws.onmessage = function (evt) {
|
||||
let node = document.createElement("div");
|
||||
node.innerHTML = "<h5>" + evt.data + "</h5>";
|
||||
show.appendChild(node);
|
||||
};
|
||||
btn.addEventListener("click", function () {
|
||||
let data = message.value;
|
||||
console.log(data);
|
||||
if (data) {
|
||||
ws.send(encodeURI(data));
|
||||
} else {
|
||||
alert("请输入消息后发送");
|
||||
}
|
||||
message.value = "";
|
||||
});
|
||||
// 关闭页面时候关闭ws
|
||||
window.addEventListener("beforeunload", function (event) {
|
||||
ws.close();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
#### 2.4 简单登录的实现
|
||||
|
||||
```java
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/login" method="post">
|
||||
<input name="username" type="text">
|
||||
<button id="btn">输入临时用户名后登录!</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```java
|
||||
/**
|
||||
* @description : 简单登录
|
||||
*/
|
||||
@Controller
|
||||
public class LoginController {
|
||||
|
||||
@PostMapping("login")
|
||||
public String login(String username, HttpSession session) {
|
||||
session.setAttribute(Constant.USER_NAME, username);
|
||||
return "chat";
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String index() {
|
||||
return "index";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -4,11 +4,7 @@ import javax.websocket.Session;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author : 罗祥
|
||||
* @description :
|
||||
* @date :create in 2018/12/27
|
||||
*/
|
||||
|
||||
public interface Constant {
|
||||
|
||||
String USER_NAME="username";
|
||||
|
@ -8,9 +8,7 @@ import org.springframework.web.bind.annotation.PostMapping;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* @author : 罗祥
|
||||
* @description : 简单登录
|
||||
* @date :create in 2018/12/27
|
||||
*/
|
||||
@Controller
|
||||
public class LoginController {
|
||||
|
@ -21,20 +21,28 @@ import java.net.URLDecoder;
|
||||
@Component
|
||||
public class ChatSocket {
|
||||
|
||||
|
||||
@OnOpen //建立连接时候触发
|
||||
/**
|
||||
* 建立连接时候触发
|
||||
*/
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("username") String username) {
|
||||
// 这个方法是线程不安全的
|
||||
Constant.nameAndSession.putIfAbsent(username, session);
|
||||
}
|
||||
|
||||
|
||||
@OnClose //关闭连接时候触发
|
||||
/**
|
||||
* 关闭连接时候触发
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose(Session session, @PathParam("username") String username) {
|
||||
Constant.nameAndSession.remove(username);
|
||||
}
|
||||
|
||||
@OnMessage //处理消息
|
||||
/**
|
||||
* 处理消息
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(Session session, String message, @PathParam("username") String username) throws UnsupportedEncodingException {
|
||||
// 防止中文乱码
|
||||
String msg = URLDecoder.decode(message, "utf-8");
|
||||
|
@ -4,12 +4,19 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
/**
|
||||
* @author : heibaiying
|
||||
*/
|
||||
@Configuration
|
||||
public class WebSocketConfig {
|
||||
|
||||
/***
|
||||
* 检测{@link javax.websocket.server.ServerEndpointConfig}和{@link ServerEndpoint} 类型的bean,
|
||||
* 并在运行时使用标准Java WebSocket时注册。
|
||||
* 我们在{@link com.heibaiying.springboot.websocket.WebSocketConfig}中就是使用@ServerEndpoint去声明websocket服务
|
||||
*/
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
|
247
spring-boot/spring-boot-yml-profile/README.md
Normal file
@ -0,0 +1,247 @@
|
||||
# spring-boot 基础
|
||||
|
||||
## 一、说明
|
||||
|
||||
#### 1.1 项目结构说明
|
||||
|
||||
1. 本项目搭建一个简单的hello spring 的 web工程,简单说明spring-boot 的开箱即用的特性;
|
||||
2. 模板引擎采用freemaker 和 thymeleaf 作为示例,分别对应模板文件makershow.ftl 和 leafShow.html;
|
||||
3. spring boot 2.x 默认是不支持jsp的,需要额外的配置,关于使用jsp的整合可以参考spring-boot-jsp项目。
|
||||
|
||||

|
||||
|
||||
#### 1.2 项目依赖
|
||||
|
||||
导入相关的starter(启动器)
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.1.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>spring-boot-base</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-boot-base</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!--模板引擎-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<!--web 启动器-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!--lombok 插件-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!--测试相关依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!--Spring Boot的Maven插件(Spring Boot Maven plugin)能够以Maven的方式为应用提供Spring Boot的支持-->
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
```
|
||||
|
||||
1. spring boot 项目默认继承自spring-boot-starter-parent,而spring-boot-starter-parent继承自spring-boot-dependencies, spring-boot-dependencies中定义了关于spring boot 依赖的各种jar包的版本,是spring boot 的版本管理中心。
|
||||
|
||||

|
||||
|
||||
2. 关于spring boot 2.x官方支持的所有starter 可以参见官方文档 [Table 13.1. Spring Boot application starters](https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#using-boot-starter)
|
||||
|
||||
|
||||
|
||||
## 二、spring boot 主启动类
|
||||
|
||||
如果采用IDEA 或者 Spring Tool Suite (STS) 等开发工具创建的spring boot 工程,会默认创建启动类,如果没有创建,需要手动创建启动类
|
||||
|
||||
```java
|
||||
package com.heibaiying.springbootbase;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringBootBaseApplication {
|
||||
|
||||
// 启动类默认开启包扫描,扫描与主程序所在包及其子包,对于本工程而言 默认扫描 com.heibaiying.springbootbase
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringBootBaseApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@SpringBootApplication 注解是一个复合注解,里面包含了@ComponentScan注解,默认开启包扫描,扫描与主程序所在包及其子包,对于本工程而言 默认扫描 com.heibaiying.springbootbase
|
||||
|
||||
```java
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
@ComponentScan(excludeFilters = {
|
||||
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
|
||||
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
|
||||
public @interface SpringBootApplication {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 三、开箱即用的web工程
|
||||
|
||||
在springbootBaseApplication.java 的同级目录创建controller文件夹,并在其中创建RestfulController.java,启动项目访问localhost:8080/restful/programmers 即可看到项目搭建成功。
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : restful 控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("restful")
|
||||
public class RestfulController {
|
||||
|
||||
@GetMapping("programmers")
|
||||
private List<Programmer> getProgrammers() {
|
||||
List<Programmer> programmers = new ArrayList<>();
|
||||
programmers.add(new Programmer("xiaoming", 12, 100000.00f, LocalDate.of(2019, Month.AUGUST, 2)));
|
||||
programmers.add(new Programmer("xiaohong", 23, 900000.00f, LocalDate.of(2013, Month.FEBRUARY, 2)));
|
||||
return programmers;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这里之所以能够开箱即用,是因为我们在项目中导入spring-boot-starter-web启动器,而@SpringBootApplication 复合注解中默认开启了@EnableAutoConfiguration注解允许开启自动化配置,spring在检查导入starter-web的依赖后就会开启web的自动化配置。
|
||||
|
||||
|
||||
|
||||
## 四、模板引擎
|
||||
|
||||
这里我们在一个项目中同时导入了freemaker 和 thymeleaf的starter(虽然并不推荐,但是在同一个项目中是可以混用这两种模板引擎的)。
|
||||
|
||||
#### 4.1 freemarker
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 跳转渲染模板引擎 默认模板的存放位置为classpath:templates
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("freemarker")
|
||||
public class FreeMarkerController {
|
||||
|
||||
@RequestMapping("show")
|
||||
private String programmerShow(ModelMap modelMap){
|
||||
List<Programmer> programmerList=new ArrayList<>();
|
||||
programmerList.add(new Programmer("xiaoming",12,100000.00f,LocalDate.of(2019,Month.AUGUST,2)));
|
||||
programmerList.add(new Programmer("xiaohong",23,900000.00f,LocalDate.of(2013,Month.FEBRUARY,2)));
|
||||
modelMap.addAttribute("programmers",programmerList);
|
||||
return "markerShow";
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>freemarker模板引擎</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<#list programmers as programmer>
|
||||
<li>姓名: ${programmer.name} 年龄: ${programmer.age}</li>
|
||||
</#list>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### 4.2 thymeleaf
|
||||
|
||||
```java
|
||||
/**
|
||||
* @author : heibaiying
|
||||
* @description : 跳转渲染模板引擎 默认模板的存放位置为classpath:templates
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("thymeleaf")
|
||||
public class ThymeleafController {
|
||||
|
||||
@RequestMapping("show")
|
||||
private String programmerShow(ModelMap modelMap) {
|
||||
List<Programmer> programmerList = new ArrayList<>();
|
||||
programmerList.add(new Programmer("xiaoming", 12, 100000.00f, LocalDate.of(2019, Month.AUGUST, 2)));
|
||||
programmerList.add(new Programmer("xiaohong", 23, 900000.00f, LocalDate.of(2013, Month.FEBRUARY, 2)));
|
||||
modelMap.addAttribute("programmers", programmerList);
|
||||
return "leafShow";
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>thymeleaf模板引擎</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul th:each="programmer:${programmers}">
|
||||
<li>
|
||||
姓名:<span th:text="${programmer.name}"></span>
|
||||
薪水:<span th:text="${programmer.salary}"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### 4.3 文档说明
|
||||
|
||||
freemarker:提供了完善的中文文档,地址 http://freemarker.foofun.cn/
|
||||
|
||||
thymeleaf:官方英文文档地址:[thymeleaf 3.0.11RELEASE](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.pdf)
|
||||
|
||||
注:我在本仓库中也上传了一份[thymeleaf中文文档(gangzi828(刘明刚 译)](https://github.com/heibaiying/spring-samples-for-all/tree/master/referenced%20documents),翻译的版本为3.0.5RELEASE
|
@ -1,10 +1,10 @@
|
||||
# 指定启动的配置
|
||||
# 指定启动的配置
|
||||
spring:
|
||||
profiles:
|
||||
active: dev
|
||||
|
||||
# 配置的补充与优先级 在dev中没有配置age,所以会采用主配置的,在prod中配置dev,会按照精确优先,使用dev中的配置
|
||||
# 更多配置的优先级可以查看项目的README.md
|
||||
# 配置的补充与优先级 在dev中没有配置age,所以会采用主配置的,在prod中配置dev,会按照精确优先,使用dev中的配置
|
||||
# 更多配置的优先级可以查看项目的README.md
|
||||
programmer:
|
||||
age: 999
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
## 二、项目依赖
|
||||
|
||||
**在父工程的项目中同一导入依赖dubbo依赖的的jar包**
|
||||
**在父工程的项目中统一导入依赖dubbo依赖的的jar包**
|
||||
|
||||
这里需要注意的是ZooKeeper 3.5.x 和 ZooKeeper 3.4.x 是存在不兼容的情况 详见官网解释[ZooKeeper Version Compatibility](https://curator.apache.org/zk-compatibility.html), zookeeper 3.5 目前是beta版本,所以zookeeper 我选择的版本是 zookeeper-3.4.9 作为服务端。但默认情况下 curator-framework自动引用的最新的3.5的版本客户端,会出现 KeeperException$UnimplementedException 异常
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
## 二、项目依赖
|
||||
|
||||
**在父工程的项目中同一导入依赖dubbo依赖的的jar包**
|
||||
**在父工程的项目中统一导入依赖dubbo依赖的的jar包**
|
||||
|
||||
这里需要注意的是ZooKeeper 3.5.x 和 ZooKeeper 3.4.x 是存在不兼容的情况 详见官网解释[ZooKeeper Version Compatibility](https://curator.apache.org/zk-compatibility.html), zookeeper 3.5 目前是beta版本,所以zookeeper 我选择的版本是 zookeeper-3.4.9 作为服务端。但默认情况下 curator-framework自动引用的最新的3.5的版本客户端,会出现 KeeperException$UnimplementedException 异常
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
### 1.1 项目结构说明
|
||||
|
||||
1. 项目模拟一个简单的群聊功能,为区分不同的聊天客户端,登录时候用临时用户名作为session的id;
|
||||
1. 项目模拟一个简单的群聊功能,为区分不同的聊天客户端,登录时候将临时用户名存储在session当中;
|
||||
2. webconfig 包是基础注解的方式配置web,在spring-base-annotation项目中已经讲解过每个类作用;
|
||||
3. CustomHander为消息的自定义处理器;
|
||||
4. CustomHandershakerInterceptor为自定义的 websocket 的握手拦截器;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
### 1.1 项目结构说明
|
||||
|
||||
1. 项目模拟一个简单的群聊功能,为区分不同的聊天客户端,登录时候用临时用户名作为session的id;
|
||||
1. 项目模拟一个简单的群聊功能,为区分不同的聊天客户端,登录时候将临时用户名存储在session当中;
|
||||
2. CustomHander为消息的自定义处理器;
|
||||
3. CustomHandershakerInterceptor为自定义的 websocket 的握手拦截器;
|
||||
4. 项目以web的方式构建。
|
||||
|