Rao's Blog

  • 首页

  • 标签

  • 分类

  • 归档

  • 搜索

Linux · 升级 glibc

发表于 2019-12-04 | 更新于 2019-12-06 | 分类于 Linux

报错信息

安装软件经常会遇到如下报错:

1
/lib64/libc.so.6: version `GLIBC_2.14' not found

出现这种报错的原因是,使用高版本的命令安装了软件,但是本机还是使用的是低版本的依赖库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ strings /lib64/libc.so.6 | grep GLIBC
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_PRIVATE

解决方法

  • 将 CentOS 6 升级到 glibc 2.15 版本
1
2
3
4
5
6
7
8
wget https://ftp.gnu.org/gnu/glibc/glibc-2.15.tar.gz
tar -zxvf glibc-2.15.tar.gz
cd glibc-2.15
mkdir build
cd build
../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin
make
make install
  • 验证是否成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ strings /lib64/libc.so.6 | grep GLIBC
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_2.13
GLIBC_2.14
GLIBC_2.15
GLIBC_PRIVATE

Linux · 免密登录

发表于 2019-12-03 | 更新于 2019-12-15 | 分类于 Linux

原理

客户端自己生成公钥私钥,然后将客户端公钥保存到服务器 ~/.ssh/authorized_keys 文件中,以后服务器都会接受客户端传过来的会话经过密钥加密过的公钥,然后解密得到公钥之后和本地 authorized_keys 配置的公钥是否相等,如果是则允许登陆。

img

操作步骤

  • 获取客户端公钥
1
2
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCl2+HlmepzqPUlJv+ESCtaYKD2pyUXlEEmmEaw5yTLv09FqD38NzaZZAmnptzOArTO/VzYX5TtNHQPpR0HApid2xMYDrF4C2BpdudobjfiJf4Mx/nzqRPbjTMNzWZJgct9iRl3lR5E9iiwiVxzOJErsaq8Dt4VoUtqVd2t5kocd5g3lvZ4b9/7ogVgLWfudtiiahx9XP3mMn7AdxnnonvSCYI/MVGIvrZAk+1Ss/0UBhgsCqGiUfaqjXfoZoJcOVCSccwl83ZXIqmLtxch46+A0YGWl/dVQSusHTJoMqmJjPm8FfyX8Cn8FaduMA4A8+RzRuox2psgjX/7Q/qg1QCF root@p-cosmo-hce

如果不存在,通过 ssh-keygen 生成密钥对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
/root/.ssh/id_rsa already exists.
Overwrite (y/n)? y
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:4qHMkrfb8bchDuoYV1DjGFy3JYzegeCidBa5yRvmBAU root@CSB-service-2
The key's randomart image is:
+---[RSA 2048]----+
| Eo++o++o . |
| . oo=ooo+ |
| .+o*..... |
|..oO .. . |
|. + o + S |
| * + o |
| + * + . . |
| * + = ... |
| ..=.. o... |
+----[SHA256]-----+
You have mail in /var/spool/mail/root
  • 将公钥保存到服务端
1
2
vi ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCl2+HlmepzqPUlJv+ESCtaYKD2pyUXlEEmmEaw5yTLv09FqD38NzaZZAmnptzOArTO/VzYX5TtNHQPpR0HApid2xMYDrF4C2BpdudobjfiJf4Mx/nzqRPbjTMNzWZJgct9iRl3lR5E9iiwiVxzOJErsaq8Dt4VoUtqVd2t5kocd5g3lvZ4b9/7ogVgLWfudtiiahx9XP3mMn7AdxnnonvSCYI/MVGIvrZAk+1Ss/0UBhgsCqGiUfaqjXfoZoJcOVCSccwl83ZXIqmLtxch46+A0YGWl/dVQSusHTJoMqmJjPm8FfyX8Cn8FaduMA4A8+RzRuox2psgjX/7Q/qg1QCF root@p-cosmo-hce
  • 测试是否可以登录
1
2
3
4
5
6
7
ssh root@10.138.225.12
The authenticity of host '10.138.225.12 (10.138.225.12)' can't be established.
ECDSA key fingerprint is SHA256:CL0QyyLYaWQDl+Gkf4NjI1Q4p9M05XM02avppepLn9k.
ECDSA key fingerprint is MD5:55:3a:a1:2c:21:7f:24:3c:65:df:d4:41:5c:e5:7e:b2.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.138.225.12' (ECDSA) to the list of known hosts.
Last login: Tue Dec 3 10:12:34 2019 from 10.138.16.192

如果出现报错信息 ssh_exchange_identification: read: Connection reset by peer,服务端执行:

1
echo "sshd:10.x.*.*" >> /etc/hosts.allow

Java · 框架 · Spring Boot

发表于 2019-11-28 | 更新于 2019-12-11 | 分类于 Java

Sping Boot 入门

简介

简化 Spring 应用开发的框架,对整个 Spring 技术栈的一个大整合,J2EE 一站式解决方案,思想约定大于配置。

创建

Spring Initializr

打包

1
2
3
4
5
6
7
8
9
<!-- 该插件可以将应用打包成一个可执行的jar包 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
1
[INFO] Building jar: /Users/raohui/Code/springboot-demo/target/springboot-demo-0.0.1-SNAPSHOT.jar

部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ java -jar springboot-demo-0.0.1-SNAPSHOT.jar 

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.1.RELEASE)

2019-11-28 16:19:15.628 INFO 79863 --- [ main] com.rao.springboot.demo.RunApplication : Starting RunApplication v0.0.1-SNAPSHOT on raohuideMacBook-Pro.local with PID 79863 (/Users/raohui/Code/springboot-demo/target/springboot-demo-0.0.1-SNAPSHOT.jar started by raohui in /Users/raohui/Code/springboot-demo/target)
2019-11-28 16:19:15.630 INFO 79863 --- [ main] com.rao.springboot.demo.RunApplication : No active profile set, falling back to default profiles: default
2019-11-28 16:19:16.292 INFO 79863 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2019-11-28 16:19:16.299 INFO 79863 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-11-28 16:19:16.300 INFO 79863 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.27]
2019-11-28 16:19:16.343 INFO 79863 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-11-28 16:19:16.343 INFO 79863 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 682 ms
2019-11-28 16:19:16.466 INFO 79863 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-11-28 16:19:16.579 INFO 79863 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-11-28 16:19:16.582 INFO 79863 --- [ main] com.rao.springboot.demo.RunApplication : Started RunApplication in 6.228 seconds (JVM running for 6.543)
2019-11-28 16:19:34.770 INFO 79863 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-11-28 16:19:34.770 INFO 79863 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-11-28 16:19:34.774 INFO 79863 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
  • pom 父项目:真正管理 Spring Boot 应用里面的所有依赖版本
1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/>
</parent>
  • 场景启动器:Starter
1
2
3
4
5
6
7
8
9
10
11
12
<!-- web模块正常运行所依赖的组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring Boot进行单元测试的模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
1
2
3
4
5
6
7
@SpringBootApplication
public class RunApplication {

public static void main(String[] args) {
SpringApplication.run(RunApplication.class, args);
}
}
  • @SpringBootApplication:这个注解说明该类是 Spring Boot 应用的主配置类,Spring Boot 就应该运行这个类的 main 方法来启动应用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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 {

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration
  • @SpringBootConfiguration:Spring Boot 的配置类,@Configuration 配置类上来标注这个注解。

  • @EnableAutoConfiguration:注解 Spring Boot 开启自动配置功能,有了自动配置类,就免去了我们手动编写配置注入功能组件等工作。

小结

Spring Boot 在启动的时候从类路径下的 META-INF/spring-factories 获取 EnableAutoConfiguration 指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作,spring-boot-autoconfigure-2.2.1.RELEASE.jar。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@RestController
@RequestMapping("api")
public class DeptController {
@Autowired
private DeptService deptService;

@Autowired
private DataScope dataScope;

private static final String ENTITY_NAME = "dept";

@Log("查询部门")
@GetMapping(value = "/dept")
@PreAuthorize("hasAnyRole('ADMIN','USER_ALL','USER_SELECT','DEPT_ALL','DEPT_SELECT')")
public ResponseEntity getDepts(DeptQueryCriteria criteria){
// 数据权限
criteria.setIds(dataScope.getDeptIds());
List<DeptDTO> deptDTOS = deptService.queryAll(criteria);
return new ResponseEntity(deptService.buildTree(deptDTOS),HttpStatus.OK);
}
}

@RestController:这个类所有方法返回的数据直接写给浏览器,如果是对象转为 json 数据。

Spring Boot 配置

全局配置文件

可以对一些默认配置值进行修改,配置文件存放在 /src/main/resources 目录或者类路径 /config 下。

  • application.properties
  • application.yml

Yaml:以数据为中心,比 json、xml 更适合做配置文件

1
2
server:
port: 8081
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.rao.springboot.demo.domain;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
* @author Rao Hui
* @date 2019-11-29 11:12
*/
@Data
@Component
@ConfigurationProperties(prefix = "person")
public class Person {

private String name;
private Integer age;
private Boolean boss;
private Date birth;

private Map<String,Object> maps;
private List<String> lists;

private Dog dog;
}

@Data:Lombok 提供,加了 @Data 注解的类,编译后会自动给我们加上下列方法:

  • 所有属性的 get() 和 set()
  • toString()
  • hashCode()
1
2
3
4
5
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>

@Component:把普通 POJO 实例化到 Spring 容器中,相当于配置文件中的 <bean id="" class=""/>

@ConfigurationProperties(prefix = “person”):默认从全局配置文件获取值,此注解将类属性和配置文件中相关配置进行绑定,一一映射。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.rao.springboot.demo.domain;

/**
* @author Rao Hui
* @date 2019-11-29 11:12
*/

import lombok.Data;

@Data
public class Dog {

private String name;
private Integer age;
private String colour;
}

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
person:
name: rao
age: 29
boss: false
birth: 2019/01/01
maps: {height: 173cm,weight: 62kg}
lists:
- lisi
- zhangsan
dog:
name: 小狗
age: 12
colour: blue

@Value 与 @ConfigurationProperties 对比:

  • 只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用 @Value
  • 专门编写 JavaBean 来和配置文件映射,使用 @ConfigurationProperties
@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定 支持 不支持
SePL 不支持 支持
JSR303 数据校验 支持 不支持
复杂类型封装 支持 不支持

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.rao.springboot.demo;

import com.rao.springboot.demo.domain.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class RunApplicationTests {

@Autowired
Person person;

@Test
void contextLoads() {
System.out.println(person.toString());
}
}
1
Person(name=rao, age=29, boss=false, birth=Tue Jan 01 00:00:00 CST 2019, maps={height=173cm, weight=62kg}, lists=[lisi, zhangsan], dog=Dog(name=小狗, age=12, colour=blue))

@Autowired:

@PropertySource(value = “classpath:person.properties”):可以加载指定位置的配置文件。

@ImportResource:导入 Spring 的配置文件,让配置文件里面的内容生效。

Spring Boot 推荐给容器中添加组件的方式:使用 @Configuration @Bean 的配置类替代配置文件给容器添加组件,容器中默认组件名就是方法名。

配置文件占位符:${}

Profile

目的:Spring 针对不同环境提供不同配置功能的支持,可以通过激活、指定参数等方式快速切换环境。

  • 多 profile 文件形式:application-{profile}.properties/yml

  • yml 支持多文档块方式:—

  • 激活指定 profile:配置文件 spring.profiles.active=dev,或者命令行 –spring.profiles.active=dev,或者虚拟机参数指定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
person:
name: rao
age: 29
boss: false
birth: 2019/01/01
maps: {height: 173cm,weight: 62kg}
lists:
- lisi
- zhangsan
dog:
name: 小狗
age: 12
colour: blue
spring:
profiles:
active: prod
---
spring:
profiles: dev
person:
name: hui
age: 29
boss: false
birth: 2019/01/01
maps: {height: 173cm,weight: 62kg}
lists:
- lisi
- zhangsan
dog:
name: 小狗
age: 12
colour: blue
---
spring:
profiles: prod
person:
name: yu
age: 29
boss: false
birth: 2019/01/01
maps: {height: 173cm,weight: 62kg}
lists:
- lisi
- zhangsan
dog:
name: 小狗
age: 12
colour: blue

配置文件加载位置:优先级由高到低,优先级高会覆盖优先级低的配置,全部加载互补配置。

  • -file:./config/
  • -file:./
  • -classpath:/config/
  • -classpath:/

Spring Boot 日志

Spring Boot:slf4j + log4j/log4j2/logback

每一个日志的实现都有自己的配置文件,使用 slf4j 之后,配置文件还是做成日志实现框架自己本身的配置文件。

Spring Boot 能自动适配所有的日志,而且底层使用 slf4j + logback 的方式记录日志,引入其他框架的时候,只需要把这个框架依赖的日志框架排除掉。

Spring Boot 与 Web 开发

模板引擎 thymeleaf

Java · Maven

发表于 2019-11-28 | 分类于 Java

简介

Maven 是当前最受欢迎的 Java 项目管理构建自动化综合工具,主要功能:

  • 统一开发规范与工具
  • 统一管理 Jar 包

仓库

Maven 根据坐标寻找构件时,首先会查看本地仓库,若本地仓库存在此构件则直接使用;若本地仓库不存在此构件,就会去远程仓库查找,查找到下载到本地仓库再使用。

分类

  • 本地仓库:默认位置 ${user.home}/.m2/repository,可通过 settings.xml 自定义
  • 中央仓库:Maven 自带的远程仓库,http://repo2.maven.org/maven2/
  • 私服:一种特殊的远程仓库,为节省带宽和时间,应在局域网内架设一个私有仓库服务器,用其代理所有外部的远程仓库。

资源库

  • 中央仓库资源:http://mvnrepository.com/ 、 https://search.maven.org/
  • 阿里云资源:http://maven.aliyun.com/nexus/content/groups/public/

核心概念

坐标

groupId,artifactId,version 三个元素是项目的坐标,唯一的标识这个项目。

  • groupId:项目所在组,一般是组织或公司
  • artifactId:是当前项目在组中的唯一 ID,一般是项目名称
  • version:表示版本
1
2
3
4
<groupId>co.yixiang</groupId>
<artifactId>yshop</artifactId>
<packaging>pom</packaging>
<version>1.3</version>

打包

  • jar:默认打包方式,我们可以在其他工程的 pom 文件中去引用它
  • war:这种打包方式是将工程都部署在服务器上,用户通过浏览器直接访问
  • pom:用在父级工程或聚合工程中,用来做 jar 包的版本控制
1
2
3
4
5
6
7
8
9
10
11
<packaging>pom</packaging>

<modules>
<module>yshop-common</module>
<module>yshop-logging</module>
<module>yshop-system</module>
<module>yshop-tools</module>
<module>yshop-generator</module>
<module>yshop-api</module>
<module>yshop-mp</module>
</modules>

概念模型

生命周期

  • Clean:目的是清理项目

    • pre-clean
    • clean:删除前一个构建生成的所有文件
    • post-clean
  • Default:定义了真正构建时所需要执行的所有步骤

    • compile:编译
    • test:测试
    • package:使用已编译的代码,并将其打包成可部署格式
    • verify:运行检查以验证包是否有效
    • install:将该包安装到本地仓库
    • deploy:将项目输出部署到远程仓库
  • Site:目的是建立和发布项目站点

    • pre-site
    • site:生成项目的站点文档
    • post-site
    • site-deploy:将生成的站点文档部署到指定的 web 服务器

标准项目结构

核心思想:约束优于配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.
├── pom.xml
├── src
│   ├── main
│   │   ├── java: 源代码目录
│   │   └── resources: 资源目录
│   └── test
│   └── java: 测试代码目录
├── target
│   ├── classes: 主体输出目录
│   ├── generated-sources
│   ├── generated-test-sources
│   └── test-classes: 测试输出目录
└── yshop-system.iml

版本规范

  • SNAPSHOT:快照版本,开发测试阶段,不稳定版本
  • LATEST:某个特定构建的最新发布版本
  • RELEASE:正式发布版本,稳定版本

Java · 框架 · MyBatis-Plus

发表于 2019-11-27 | 更新于 2019-11-28 | 分类于 Java

官方网站:https://mybatis.plus/

GitHub:https://github.com/baomidou/mybatis-plus

功能:

  • 强大的 CRUD 操作
  • 主键自动生成
  • 强大的代码生成器

引入

1
2
3
4
5
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.2.0</version>
</dependency>

Java · 框架 · JPA

发表于 2019-11-27 | 更新于 2019-11-28 | 分类于 Java

ORM

简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,对象-关系映射(Object/Relational Mapping) 的缩写,ORM 的主要功能是把数据库映射成对象。

  • 数据库表(table)–> 类(class)

  • 记录(record,行数据)–> 对象(object)

  • 字段(field)–> 对象的属性(attribute)

示例

1
2
3
4
5
6
7
8
# 数据库写法
SELECT id, first_name, last_name, phone, birth_date, sex FROM person WHERE id = 10

# ORM写法
p = Person.get(10);
name = p.first_name;
phone = p.phone
...

现在 Dao 持久层的解决方案中,大部分是采用 Spring Data JPA 或 MyBatis 解决方案,并且传统企业多用前者,互联网企业多用后者。Spring Data JPA 是 Spring Data 在 JPA 和 ORM 框架之间抽象封装层,它不直接代替 ORM 框架,默认低层使用的 ORM 框架是 Hibernate。

JPA

Java Persistence API,可以通过注解或者 XML 描述对象-关系表之间的映射关系,并将实体对象持久化到数据库中,JPA 是一套 ORM 规范。

Spring Data JPA:是 Spring 提供的一套简化 JPA 开发的框架,按照约定好的方法命名规则写 dao 层接口,就可以在不写接口实现的情况下,实现对数据库的访问和操作,可以理解为 JPA 规范的再次封装抽象,底层还是使用了 Hibernate 的 JPA 技术实现。

接口约定命名规则

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,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, Null findByAge(Is)Null … 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 ?%
EndingWith findByFirstnameEndingWith … where x.firstname like %?
Containing findByFirstnameContaining … where x.firstname like %?%
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection 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)

maven 坐标

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

yml 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#配置数据源
spring:
datasource:
druid:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:mysql://localhost:3306/yshop
username: root
password: root

#配置 Jpa
jpa:
hibernate:
# 生产环境设置成 none,避免程序运行时自动更新数据库结构
ddl-auto: update

JPA vs MyBatis

Mybatis

优点:

  • SQL 语句可以自由控制,更灵活,性能更高
  • SQL 与代码分离,易于阅读和维护
  • 提供 XML 标签,支持动态 SQL 语句

缺点:

  • 简单 CRUD 操作还得写 SQL 语句
  • XML 中有大量的 SQL 需要维护
  • MyBatis 自身功能有限,但支持 Plugin

JPA

优点:

  • 移植性比较好
  • 提供了很多 CRUD 方法,开发效率高
  • 对象化程度高

缺点:

  • 框架比较重,学习成本较高
  • 性能不好控制

Java · 项目 · yshop

发表于 2019-11-26 | 更新于 2019-12-24 | 分类于 Java

简介

yshop 基于当前流行技术组合的前后端分离商城系统, 包含商城、拼团、砍价、 秒杀、优惠券、积分、分销等功能,适合企业或个人二次开发。

  • 体验:https://yshop.dayouqiantu.cn
  • 登录:admin/123456

项目结构

  • yshop-api:公众号 API 模块(H5)
  • yshop-mp:微信相关模块
  • yshop-common:公共模块
  • yshop-system:商城系统模块
  • yshop-logging:日志模块
  • yshop-tools:第三方工具模块
  • yshop-generator:代码生成模块

后端技术

  • Spring Boot
  • MyBatis、MyBatis-Plus
  • Spring Security
  • JPA
  • Druid
  • Slf4j
  • fastjson
  • JWT
  • Redis
  • Quartz
  • MySQL
  • Swagger
  • WxJava
  • Lombok
  • Hutool
  • Mapstruct

前端技术

  • Vue
  • Element

商城功能

  • 商品模块:商品添加、规格设置,商品上下架等
  • 订单模块:下单、购物车、支付,发货、收货、评价、退款等
  • 营销模块:积分、优惠券、分销、砍价、拼团、秒杀(、到店核销等
  • 微信模块:自定义菜单、自动回复、微信授权、图文管理、模板消息推送
  • 配置模块:各种配置
  • 用户模块:登陆、注册、会员卡等
  • 其他等

知识留存率

发表于 2019-11-26 | 分类于 其他

Java · 框架 · Spring

发表于 2019-11-25 | 分类于 Java

Spring IOC

IOC:Inversion Of Control,即控制反转,是一种设计思想。在传统的 Java SE 程序设计中,我们直接在对象内部通过 new 的方式来创建对象,是程序主动创建依赖对象;而在 Spring 程序设计中,IOC 是有专门的容器去控制对象。

控制:就是对象的创建、初始化、销毁。

反转:其实是反转的控制权,前面提到是由 Spring 来控制对象的生命周期,那么对象的控制就完全脱离了我们的控制,控制权交给了 Spring 。

  • 创建对象:原来是 new 一个,现在是由 Spring 容器创建。
  • 初始化对象:原来是对象自己通过构造器或者 setter 方法给依赖的对象赋值,现在是由 Spring 容器自动注入。
  • 销毁对象:原来是直接给对象赋值 或做一些销毁操作,现在是 Spring 容器管理生命周期负责销毁对象。

总结:IOC 解决了繁琐的对象生命周期的操作,降低程序间的耦合(依赖关系)。

DI:Dependency injection,即依赖注入,是一种实现,而 IOC 是一种设计思想。程序把依赖交给容器,容器帮你管理依赖,这就是依赖注入的核心。

使用

1
2
3
4
5
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>

Nginx 笔记

发表于 2019-11-25 | 更新于 2020-03-23 | 分类于 Nginx

简介

Nginx:是一款轻量级的 Web 服务器、反向代理服务器,由于它的内存占用少(一个 worker 进程只占用 10-12M 内存)、启动极快、高并发能力强,在互联网项目中广泛应用。

代理

正向代理

由于防火墙的原因,我们并不能直接访问谷歌,那么我们可以借助 VPN 来实现,这就是一个简单的正向代理的例子。这里你能够发现,正向代理“代理”的是客户端,客户端是知道目标的,而目标是不知道客户端是通过 VPN 访问的。

反向代理

当我们在外网访问百度的时候,其实会进行一个转发,代理到内网去,这就是所谓的反向代理,即反向代理“代理”的是服务器端,而且这一个过程对于客户端而言是透明的。

web 服务器对比

对比项 \ 服务器 Apache Nginx Lighttpd
Proxy代理 非常好 非常好 一般
Rewriter 好 非常好 一般
Fcgi 不好 好 非常好
热部署 不支持 支持 不支持
系统压力 很大 很小 比较小
稳定性 好 非常好 不好
安全性 好 一般 一般
静态文件处理 一般 非常好 好
反向代理 一般 非常好 一般

负载均衡

负载均衡作为流量转发服务,将来自客户端的请求通过负载均衡集群转发至后端服务器,后端服务器再将响应通过内网返回给负载均衡。基础架构是采用集群部署,提供四层(TCP 协议和 UDP 协议)和七层(HTTP 和 HTTPS 协议)的负载均衡,可实现会话同步,以消除服务器单点故障,提升冗余,保证服务的稳定性。

  • 硬件负载均衡:是直接在服务器和外部网络间安装负载均衡设备,这种设备通常是一个独立于系统的硬件,我们称之为负载均衡器,例如 F5。
  • 软件负载均衡:是指在一台或多台服务器相应的操作系统上安装一个或多个附加软件来实现负载均衡,例如 Nginx、LVS。
  • 四层负载均衡:是指基于IP + 端口的负载均衡,常见例子有:LVS,F5。
  • 七层负载均衡:是基于虚拟URL或主机IP的负载均衡,常见例子有: HAProxy,MySQL Proxy。

Nginx 进程

启动 Nginx 后,其实就是在 80 端口启动了 Socket 服务进行监听,Nginx 涉及 Master 进程和 Worker 进程。

  • Master 进程:读取并验证配置文件 nginx.conf,管理 worker 进程。
  • Worker 进程:每一个 Worker 进程都维护一个线程(避免线程切换),处理连接和请求,Worker 进程的个数由配置文件决定,一般和 CPU 个数相关(有利于进程切换),配置几个就有几个 Worker 进程。

思考1:Nginx 如何做到热部署?

所谓热部署,就是配置文件 nginx.conf 修改后,不需要 stop nginx,不需要中断请求,就能让配置文件生效!

实现方案:修改配置文件 nginx.conf 后,重新生成新的 worker 进程,当然会以新的配置进行处理,而且新的请求都必须交给新的 worker 进程,至于老 worker 进程,等把那些以前的请求处理完毕,kill 掉即可。

思考2:Nginx 如何做到高并发下的高效处理?

实现方案:Nginx 采用了 Linux 的 epoll 模型,epoll 模型基于事件驱动机制,它可以监控多个事件是否准备完毕,如果 OK,那么放入 epoll 队列中,这个过程是异步的,worker 只需要从 epoll 队列循环处理即可。

思考3:Nginx 挂了怎么办?

实现方案:Keepalived + Nginx 实现高可用

  • 请求不要直接打到 Nginx 上,应该先通过 Keepalived(这就是所谓虚拟 IP,VIP),消除单点故障
  • Keepalived 应该能监控 Nginx 的生命状态(提供一个用户自定义的脚本,定期检查 Nginx 进程状态,进行权重变化,从而实现 Nginx 故障切换)

安装

  • 安装
1
2
rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
yum install -y nginx
  • 路径
1
2
3
4
5
6
7
8
$ whereis nginx
nginx: /usr/sbin/nginx /usr/lib64/nginx /etc/nginx /usr/share/nginx /usr/share/man/man8/nginx.8.gz

- Nginx配置路径:/etc/nginx/nginx.conf
- PID目录:/var/run/nginx.pid
- 错误日志:/var/log/nginx/error.log
- 访问日志:/var/log/nginx/access.log
- 默认站点目录:/usr/share/nginx/html

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
server_name zentao.smocer.top;

access_log /var/log/nginx/zentao.access.log;

location / {
try_files /_not_exists_ @backend;
}

location @backend {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;

proxy_pass http://10.133.0.53:8080;
}

常用命令

启动

1
nginx

检查配置

1
nginx -t

热加载

1
nginx -s reload

查询进程

1
ps -ef | grep nginx

停服务

1
nginx -s stop

FAQ

Nginx 启动成功,加载页面,报错 ERR_CONTENT_LENGTH_MISMATCH

错误日志:

1
2020/03/23 17:20:17 [crit] 87961#0: *419 open() "/usr/local/var/run/nginx/proxy_temp/5/08/0000000085" failed (13: Permission denied) while reading upstream, client: 127.0.0.1, server: x-dev.qd-ctcc.haier.net, request: "GET /console/vendors~alarm.js HTTP/1.1", upstream: "http://127.0.0.1:8040/console/vendors~alarm.js", host: "x-dev2.qd-ctcc.haier.net", referrer: "http://x-dev2.qd-ctcc.haier.net/console"

原因分析:

Nginx 在压力之下,试图从它的缓存中拉取 /usr/local/var/run/nginx/,但是由于权限问题无法访问。出现这个问题的根本原因是使用管理员账号启动了 Ngnix,然后又使用普通账号启动了一次导致无法访问缓存目录。

解决办法:

使用管理员账号删除 /usr/local/var/run/nginx/proxy_temp 目录缓存,然后使用非管理员账号重启 Nginx。

1…456…18
Hui Rao

Hui Rao

最好的成长是分享
173 日志
19 分类
14 标签
GitHub E-Mail
© 2021 Hui Rao
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Gemini v7.1.0
|