文章目录
1、spring boot
1.1、先看看spring mvc的注解
该思维导图地址:https://www.processon.com/special/template/5db2f438e4b0335f1e407f92#map
1.2、spring boot注解总结
凡是子类及带有方法或属性的类都要加上注册Bean到Spring IoC的注解
把Bean理解为类的代言人,这样它就能代表类拥有该东西了
该思维导图地址:https://www.processon.com/view/5d9b0d4fe4b03347e133c512#map
声明为SpringBean的注解
- @Controller 标记为Controller(控制器里面是各个路径,用在类上)
- @Service 标记为Service,加在实现类上
- @Repository 标记为DAO,mybatis中不需要
- @Component 其他组件,比如pojo实体类,以上三个都不是的用这个
@Restcontroller= @Controller+@ResponseBod
@ResponseBody的作用其实是将java对象转为json格式的数据。
自动注入
- @Autowired 自动装配,不用new对象了,按byType自动注入(用在变量上)
- @Resource 自动装配,不用new对象了,按 byName自动注入,jdk提供,spring也支持 (用在变量上)
- @Value 注入值,内容为SPEL表达式
配置bean
- @Configuration 标记为配置类,代替springmvc的xml配置,里面都是bean,用在类上
- @Bean 标记为一个Bean,用在方法上
- @Import 配置类,用于导入其他配置类,用在类上
@Bean(initMethod=“加载”,destoryMethod=“销毁”)
1.3、spring boot注解详细
@Autowired
作用:定义在变量头上,就不用手动new这个对象了。
它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。
@Configuration
作用:定义配置类,可替换xml配置文件。相当于bean的盒子,里面装的全是bean
被注解的类内部包含有一个或多个被@Bean注解的方法,用于构建bean定义,用@Configuration定义的类会被扫描。
例:
@Bean
作用:和xml配置中的bean标签的作用是一样的,只放在方法上。
一个方法头上加bean,最后就会被扔到spring容器里面。
@Component , @Repository , @ Controller , @Service , @Configration这些注解就是用于注册Bean。
@Autowired , @Resource注解用来拿Bean的
例:
@Import
作用:将没有被Spring容器管理的类导入至Spring容器中。
@Import只能用在类上,可以用于导入第三方包 ,当然@Bean注解也可以,但是@Import注解快速导入的方式更加便捷。
使用:https://www.cnblogs.com/zhoading/p/12194960.html
@service
作用:标注业务层组件
@ComponentScan
作用:@ComponentScan(value=包路径),告诉Spring 这个包需要扫描。
并找到这个包里标注有@Component,@Controller,@Service,@Repository 注解的类,将这些类自动加载到 Spring 容器中。
例:
@SpringBootApplication
作用:告诉spring这是程序入口
@SpringBootApplication注解也包含了@ComponentScan注解,也可以告诉它哪些包需要扫描。
例:
2、springboot + HttpClient (爬虫)
以下列出的是 HttpClient 提供的主要的功能,要知道更多详细的功能可以参见 HttpClient 的主页。
-
实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)
-
支持自动转向
-
支持 HTTPS 协议
-
支持代理服务器等
2.1、第一个get示例
先加入依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4</version>
</dependency>
新建类jGet.java
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class Get {
public static void main(String[] args) throws Exception {
// 创建Httpclient对象,相当于打开了浏览器
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建HttpGet请求,相当于在浏览器输入地址
HttpGet httpGet = new HttpGet("http://www.baidu.com/");
CloseableHttpResponse response = null;
try {
// 执行请求,相当于敲完地址后按下回车。获取响应
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
// 解析响应,获取数据
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}
} finally {
if (response != null) {
// 关闭资源
response.close();
}
// 关闭浏览器
httpclient.close();
}
}
}
运行后就输出html
把以上代码简化一下,方便看
public class Get {
public static void main(String[] args) throws Exception {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://www.baidu.com/");
// 执行请求
CloseableHttpResponse response = httpclient.execute(httpGet);
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}
}
2.2、带参数的Get请求
public class DoGETParam {
public static void main(String[] args) throws Exception {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建URI对象,并且设置请求参数
URI uri = new URIBuilder("http://www.baidu.com/s").setParameter("wd", "java").build();
// 创建http GET请求
HttpGet httpGet = new HttpGet(uri);
CloseableHttpResponse response = null;
try {
// 执行请求
response = httpclient.execute(httpGet);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
// 解析响应数据
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}
} finally {
if (response != null) {
response.close();
}
httpclient.close();
}
}
}
2.3、POST请求
public class DoPOST {
public static void main(String[] args) throws Exception {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建http POST请求
HttpPost httpPost = new HttpPost("http://www.oschina.net/");
// 把自己伪装成浏览器。否则开源中国会拦截访问
httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
CloseableHttpResponse response = null;
try {
// 执行请求
response = httpclient.execute(httpPost);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
// 解析响应数据
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}
} finally {
if (response != null) {
response.close();
}
// 关闭浏览器
httpclient.close();
}
}
}
2.4、带参数POST请求
public class DoPOSTParam {
public static void main(String[] args) throws Exception {
// 创建Httpclient对象
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建http POST请求,访问开源中国
HttpPost httpPost = new HttpPost("http://www.oschina.net/search");
// 根据开源中国的请求需要,设置post请求参数
List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);
parameters.add(new BasicNameValuePair("scope", "project"));
parameters.add(new BasicNameValuePair("q", "java"));
parameters.add(new BasicNameValuePair("fromerr", "8bDnUWwC"));
// 构造一个form表单式的实体
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);
// 将请求实体设置到httpPost对象中
httpPost.setEntity(formEntity);
CloseableHttpResponse response = null;
try {
// 执行请求
response = httpclient.execute(httpPost);
// 判断返回状态是否为200
if (response.getStatusLine().getStatusCode() == 200) {
// 解析响应体
String content = EntityUtils.toString(response.getEntity(), "UTF-8");
System.out.println(content);
}
} finally {
if (response != null) {
response.close();
}
// 关闭浏览器
httpclient.close();
}
}
}
2.5、与springboot整合
添加依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
配置
http.maxTotal=300
http.defaultMaxPerRoute=50
http.connectTimeout=1000
http.connectionRequestTimeout=500
http.socketTimeout=5000
http.staleConnectionCheckEnabled=true
在类中编写代码
@Configuration
@ConfigurationProperties(prefix = "http", ignoreUnknownFields = true)
public class HttpClientConfig {
private Integer maxTotal;// 最大连接
private Integer defaultMaxPerRoute;// 每个host的最大连接
private Integer connectTimeout;// 连接超时时间
private Integer connectionRequestTimeout;// 请求超时时间
private Integer socketTimeout;// 响应超时时间
/**
* HttpClient连接池
* @return
*/
@Bean
public HttpClientConnectionManager httpClientConnectionManager() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(maxTotal);
connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
return connectionManager;
}
/**
* 注册RequestConfig
* @return
*/
@Bean
public RequestConfig requestConfig() {
return RequestConfig.custom().setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout)
.build();
}
/**
* 注册HttpClient
* @param manager
* @param config
* @return
*/
@Bean
public HttpClient httpClient(HttpClientConnectionManager manager, RequestConfig config) {
return HttpClientBuilder.create().setConnectionManager(manager).setDefaultRequestConfig(config)
.build();
}
@Bean
public ClientHttpRequestFactory requestFactory(HttpClient httpClient) {
return new HttpComponentsClientHttpRequestFactory(httpClient);
}
/**
* 使用HttpClient来初始化一个RestTemplate
* @param requestFactory
* @return
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory requestFactory) {
RestTemplate template = new RestTemplate(requestFactory);
List<HttpMessageConverter<?>> list = template.getMessageConverters();
for (HttpMessageConverter<?> mc : list) {
if (mc instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) mc).setDefaultCharset(Charset.forName("UTF-8"));
}
}
return template;
}
public Integer getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(Integer maxTotal) {
this.maxTotal = maxTotal;
}
public Integer getDefaultMaxPerRoute() {
return defaultMaxPerRoute;
}
public void setDefaultMaxPerRoute(Integer defaultMaxPerRoute) {
this.defaultMaxPerRoute = defaultMaxPerRoute;
}
public Integer getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(Integer connectTimeout) {
this.connectTimeout = connectTimeout;
}
public Integer getConnectionRequestTimeout() {
return connectionRequestTimeout;
}
public void setConnectionRequestTimeout(Integer connectionRequestTimeout) {
this.connectionRequestTimeout = connectionRequestTimeout;
}
public Integer getSocketTimeout() {
return socketTimeout;
}
public void setSocketTimeout(Integer socketTimeout) {
this.socketTimeout = socketTimeout;
}
}
3、svn代码管理工具
SVN:集中式版本控制器。严重的依赖服务器端,当服务器端无法使用的时候,版本控制也就无法再使用了。
Git:分布式版本控制系统。当这个系统的任何一个客户端出现问题的时候,都可以从另外的客户端(即使服务器挂了)获取所有的代码。
SVN 代码托管站:https://svnbucket.com/
3.1、服务端搭建
使用软件:Setup Subversion和TortoiseSVN
Subversion下载地址:http://www.itmop.com/downinfo/131799.html
TortoiseSVN下载地址:https://dl.pconline.com.cn/download/53122-1.html
安装的时候注意一下,不要安装在有空格的文件夹下(默认安装路径就有空格)
两个软件安装成功后,系统的环境变量里面自动就有对应的path了
在cmd查看版本信息:svn --version
新建一个文件夹SvnRep作为svn仓库,再新建一个文件夹app1,作为项目根目录
输入指令,将app1指定为项目的仓库:svnadmin create F:\SvnRep\app1
指定完成之后app1从一个空文件夹,变成了这样
启动本地库:svnserve -d -r F:\SvnRep\app1
启动后这个cmd窗口就不要关闭,关闭了svn仓库服务也就关闭了
-d表示 后台执行,-r表示版本库根目录。
然后打开一个新的cmd窗口,输入netstat -an,可以查看端口状态
3.2、把svn服务注册为windows启动服务
在cmd输入:sc create SUNservice binpath= “F:\svn\sub\bin\svnserve.exe --service -r F:\SvnRep” start= auto depend= Tcpip
注意如上指令,等于左边都是紧贴,右边一个空格加上值
binpath是Subversion的bin目录下的svnserve.exe
-r后面的是仓库目录
如果这里出现错误5:拒绝访问,那就用管理员权限打开cmd试试
如果想删除这个服务,可以输入:sc delete SUNservice
查看windows下都有哪些服务:快捷键win+R,输入services.msc
启动服务
启动完成,在配置文件里面把app1项目的可读写权限打开
3.3、客户端
3.3.1、上传文件
新建一个app1文件夹,假设这里面存满了我们的项目文件。
使用cmd切到当前目录下,然后检查当前目录版本信息
svn checkout svn://localhost/app1
检查完之后目录下多了一个文件夹
在app1文件夹下新放入1.txt文件
现在将1.txt加入版本控制器:svn add 1.txt
然后提交:svn commit -m “第一次提交” 1.txt
3.3.2、在新地方取文件
我们新建一个文件夹aa,然后:svn checkout svn://localhost/app1
再查看目录,文件就有了
之后想要更新某个文件的版本,就用:svn update 1.txt
上传新版本就用:svn commit -m “第二次提交” 1.txt
提交新文件就用:svn add 2.txt
3.3.3、idea与svn
eclipce和idea都有svn的插件,这里以idea为例。
安装TortoiseSVN
TortoiseSVN下载地址:https://dl.pconline.com.cn/download/53122-1.html
安装完成打开idea项目,选择subversion
这一步之后需要重启,添加仓库地址
上传项目
再查看就有了
上一步除了上传到本地仓库以外,还可以传到云托管平台,比如:https://svnbucket.com
4、springboot+mybatis-plus
mybatis-plus官网:http://mp.baomidou.com
1、导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
2、配置mysql连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Hongkong
spring.datasource.username=root
spring.datasource.password=12345678
在mysql中新建一个数据库mp,并建一个表user
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
插入两条数据
INSERT INTO `user` VALUES ('1', '张三', '16', '113333');
INSERT INTO `user` VALUES ('2', '李四', '17', '2232');
3、建一个实体类User
idea中使用lombok记得安装这个插件
4、建一个UserMapper接口继承自BaseMapper<User>
5、让应用扫描mapper:@MapperScan(“mapper的包路径”)
6、在测试方法中测试
首先注入UserMapper
可以看到idea会有一个报错,这个错误可以忽略,如果想解决,也可以在UserMapper接口上加一个@Component注解。
现在来查询所有用户
List<User> users = userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
测试结果
4.1、日志配置
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
4.2、通过id,增删改
增
如上代码返回的r是 sql影响的行数
删
改
4.3、mybatis-plus的id生成策略
如4.2中“增”的例子:
运行后,查看数据库
id生成策略:19位,由snowflake算法生成
分布式的id生成策略:分表存储
1、id由mysql数据库自动增长,(oracle数据库不支持自动增长)
2、redis原子操作
3、mybatis-plus自带的snowflake算法生成id
4、利用zoomkeeper生成唯一ID
5、MangoDB的ObjectID,与snowflake算法类似
更改id生成策略
type有这些值,其中第二个就是默认类型
4.4、时间的自动填充
在user表里添加create_time和update_time两个字段
然后在实体类添加这两个字段,并自动填充
@TableField(fill = FieldFill.INSERT)
private Date createTime; // 创建时间
@TableField(fill = FieldFill.UPDATE)
private Date updateTime; // 修改时间
配置自动填充内容(重写insertFill、updateFill方法)
@Component
public class MetaHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
4.5、悲观锁、乐观锁与自动填充
数据库操作中的丢失更新问题
例:有一条数据A,m和n同时去更改,结果为最后提交m改的数据,n改的内容就被丢失了。
解决这个问题的办法:乐观锁、悲观锁
悲观锁:只允许一个人操作,操作完之后才允许下一个人操作
悲观锁缺点:效率太低
乐观锁:给每次提交的数据加上版本号。每次提交会查看当前操作的版本号,如果提交时和获取时版本号不一样就不能提交。
在mybatis-plus中使用乐观锁。
添加字段version
表里加
实体类加
配置乐观锁插件
@EnableTransactionManagement
@Configuration
public class MybatisConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
然后测试乐观锁执行效果
更新数据前
更新数据后
4.6、批量操作、条件查询
根据id批量查询
List<User> users = userMapper.selectBatchIds(Arrays.asList(1L,2L,3L));
map简单条件查询
Map<String,Object> map = new HashMap<>();
map.put("age",17);
map.put("name","张三");
List<User> users = userMapper.selectByMap(map);
// 注意这里map对应的k是数据库中的字段名,不是实体类的属性名
4.7、分页
1、配置分页插件
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
2、使用
// page后面的参数:当前页、每页个数
Page<User> page = new Page<>(1,3);
userMapper.selectPage(page,null);
long c = page.getCurrent(); // 当前页数
long size = page.getSize(); // 每页多少条
List<User> r = page.getRecords(); // 每页的数据
long pages = page.getPages(); // 总页数
long total = page.getTotal(); // 数据总条数
boolean b = page.hasPrevious(); // 是否有上一页
boolean b1 = page.hasNext(); // 是否有下一页
如上使用的是对象的方式获取数据,mybatis-plus还提供了map的方式
IPage<Map<String,Object>> iPage = userMapper.selectMapsPage(page,null);
List<Map<String, Object>> r2 = iPage.getRecords(); // 每页的数据
有一个快速循环输出getRecords()的方法
iPage.getRecords().forEach(System.out::println);
4.8、条件删除、逻辑删除
根据字段信息删除
逻辑删除
做了逻辑删除后,mybatis-plus的查询会自动不查逻辑删除的数据
1、在数据表加上逻辑删除字段
2、在实体类添加属性
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Boolean deleted;
3、配置默认添加值
4、配置逻辑删除插件
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
5、如果你的逻辑删除符号不是0、1可以配置一下
6、使用逻辑删除
直接使用userMapper.deleteById();就可以逻辑删除
4.9、wapper条件构造器
类继承关系图
例:按照条件删除一条数据
如上的构造器方法分别有
ge :大于等于
gt :大于
le :小于等于
lt :小于
eq :等于
ne:不等于
isNull :为空
isNotNull :不为空
between :在多少到多少之间
between例 : wrapper.between(“age”,20,30);
例:按照条件查询数据
还有其他的构造器方法
allEq、like、notLike、likeLeft、likeRight、or、and、orderByDesc(排序升序)、orderBy、orderByAsc
还可以指定查询的字段
还可以指定拼接语句:last
last只能调用一次,且有sql注入风险
5、springboot项目版本区别
Spring Boot 2.x
Tomcat 8.5
Flyway 5
Hibernate 5.2
Thymeleaf 3
1、java最低需要 jdk 1.8
2、WebMvcConfigurerAdapter这个抽象类已经过时,WebMvcConfigurerAdapter 被 WebMvcConfigurer 接口替代了,可以直接继承 WebMvcConfigurer 接口然后实现他的default方法即可。
3、拦截器不会对静态资源默认放行,静态资源放在 /asserts 和 /webjars 中,/**会统配所有的资源,这样拦截器就不会拦截。
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerIntercepter()).addPathPatterns("/**")
.excludePathPatterns("/asserts/**","/webjars/**");
}
4、mysql配置不一样,(url后面必须要有时区)
spring.datasource.url: jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Hongkong
spring.datasource.driver-class-name: com.mysql.cj.jdbc.Driver
spring.datasource.username: root
spring.datasource.password: root
2、底层使用的spring5.x,注解功能更强大
Spring Boot 1.x
1、mysql配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mp
spring.datasource.username=root
spring.datasource.password=root
2、底层使用的spring4.x