SpringBoot学习
SpringBoot是一个快速开发Spring应用的脚手架,简化Spring的初始配置和开发过程
- 内置很多Starter结合自动配置,开箱即用
- 内置web服务器,省略web.xml配置,可以直接运行jar启动web应用
- SpringBoot帮我们管理第三方依赖版本,解决的版本冲突问题
- 自带监控功能,监控应用程序的运行、内存等
核心思想:约定>配置(通过遵循一些预设的规则和模式来简化应用程序的配置过程。)
Spring与SpringBoot
SpringBoot是SpringFramework生态的一个产品,同时Spring Framework是一块框架,springBoot是Spring的脚手架,可以更快的开发Spring
特点
1.自动配置
2. 内置Tomcat、jetty(无需部署WAR文件)
3. 外部化配置
4. 不需要xml配置,只需要少量的properties/yml
5. boot父工程会帮我们管理boot中的依赖版本
微服务
微服务是一种云原生的架构方法,它通过将应用程序分解为一系列小型、松散耦合的服务来提高系统的灵活性和可维护性,目的是达到高内聚,低耦合。
- 功能分解:将功能分解到各个离散的服务中实现解决方案的解耦,每个服务负责应用的一个特定功能。
- 独立部署:这些服务可以独立的部署,不同的服务可以采用不同的技术栈,而不必更新整个应用
- 通信机制:微服务之间通过REST API、事件流和消息代理等方式通信,有助于时间服务间的通信
总的来说,微服务架构提供了一种灵活、可扩展的方式来构建和维护复杂的应用程序。它适用于大型和复杂的系统,尤其是那些需要快速迭代和频繁更新的应用。然而,微服务架构也带来了一些挑战,如服务间的通信复杂性、数据一致性问题以及部署和管理的复杂性。因此,在采用微服务架构时,需要仔细考虑这些因素,并确保有足够的技术和管理能力来应对这些挑战。
SpringBoot核心注解
- @SpringBootApplication:启动类注解
- @Configuation:配置类
- @EnableAtuoConfiguation:自动配置类
- @ConditionalOnxxx:判断是否启用bean
创建一个SpringBoot程序
Web下勾选Spring Web Start,(网上创建springboot项目多是勾选Web选项,而较高版本的Springboot没有此选项,勾选Spring Web Start即可,2.1.8版本是Spring Web);Template Englines勾选Thymeleaf;SQL勾选:MySQL Driver,JDBC API 和 MyBatis Framework三项;点击next
自动配置原理(重点)
简介:SpringBoot通过自动装配将第三方bean自动的装配到IOC容器中,不许再去写额外的配置
- 通过启动类中@SpringBootConfiguration(复合注解)引入了@EnableAutoConfiguation注解(负责启动自动配置功能)
- @EnableAutoConfiguation引入了@Import注解
- 这个注解利用 SpringFactoriesLoader 机制来加载 META-INF/spring.factories 文件中配置的所有配置类的路径
- spring.factories 文件:这个文件位于 Spring Boot 各个自动配置模块的 META-INF 目录下,列出了所有可用的自动配置类(AutoConfiguration 类)的路径,这些类通常是用 @Configuration 注解标注的,用来做条件化的配置。
- 配置类存放在第三方jar中,配置类中存在@ConditionalOnWebApplication、@ConditionalOnClass等注解判断条件判断是否注入到Spring容器中;配置类中使用@Bean声明要注册到IOC容器中的对象
扩展自动装配(Spring)
在Spring中通过一下四个方式实现自动装配:
- 构造函数:通过带参构造函数实现注入
- set方法:通过set方法调用注入
- 字段注入:通过直接访问对象的字段,Spring可以将依赖项赋值给相应的字段
- 注解注入:@Autowired和@Resource注解
yml与properties配置文件
在yml中使用key:空格value格式
server:
port: 8080
在properties中使用key=value
server.port=8080
mybatis开启驼峰命名与下划线命名的转换
mybatis:
configuration:
map-underscore-to-camel-case: true #开启驼峰命名到下户线命名的转换
@Validated注解
// JSR提供的校验注解:
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
// Hibernate Validator提供的校验注解:
@NotBlank(message =) 验证字符串非null,且长度必须大于0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
静态资源
静态资源可以存放在public、resources、static中可以,首页名称定义为index.html,不能放在templates中,这里面只能controller中跳转进来。
---------------------------2024-05-17------------------------------
thymeleaf模板引擎
thymeleaf会在templates文件夹下寻找.html文件
省略前端
Spring连接数据库
YML配置数据库信息信息
spring:
datasource:
username: root
password: 1111
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
JdbcTemplate
Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作。
@Autowired
JdbcTemplate jdbcTemplate;
@RequestMapping("/list")
public List<Map<String,Object>> userList(){
String sql = "select * from user";
List<Map<String,Object>> list = jdbcTemplate.queryForList(sql);
return list;
}
Restful风格
- 在请求controller中的接口时可以通过不同的请求方式来请求同一个地址但实现调用不同的接口
- 在参数方便通过给参数添加@Pathvariable来实现传参
@RequestMapping("/update/{id}")
public String updateUser(@PathVariable("id") int id ){
String sql = "update user set name=?,pwd=? where id= "+id;
Object [] object = new Object[2];
object[0] = "周新泽";
object[1] = "0628";
int result = jdbcTemplate.update(sql, object);
if(result>0){
return "success!";
}else{
return "failed!";
}
}
——————-----2024-05-1--------------------------------------
DRUID(德鲁伊)
结合c3p0、DBCP等,并加入了日志监控。
导入DRUID依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.3</version>
</dependency>
整和Mybatis
配置数据库连接properties文件
server.port=8080
spring.datasource.username=root
spring.datasource.password=1111
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#整合Mybatis
mybatis.type-aliases-package=com.qdu.www.entity
mybatis.mapper-locations=classpath:Mapper/*.xml
mapper.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.qdu.www.Mapper.UserMapper">
<select id="userList" resultType="user">
select * from user
</select>
</mapper>
BIG-EVENT项目
参数校验
传统方式
public Result register(String username,String password){
if(username != null && username.length()>=5 && username.length()<=16&&
password != null && password.length() >= 5 && password.length() <= 16){
//查询用户名是否被占用
User u = userService.findUserByName(username);
//没有被占用则注册
if(u == null || !u.getUsername().equals(username)){
userService.register(username,password);
return Result.success();
}else{
// 被占用返回失败
return Result.error("用户名被占用!");
}
}else{
return Result.error("参数不合规!");
}
}
@Validated注解
@Pattern(regexp="^\\S{5,16}$") String username, @Pattern(regexp="^\\S{5,16}$")String password
使用之后会在报错500,在后台显示错误,我们需要通过一个全局异常处理器来解决
package com.event.Exception;
import com.event.pojo.Result;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result handlerException(Exception e){
e.printStackTrace();
return Result.error(StringUtils.hasLength(e.getMessage())?e.getMessage():"操作失败");
}
}
登录认证
用户在登录之前不能访问除了注册和登录之外接口,这就需要用户的登录认证来管理,在访问时对其令牌进行检查,如果携带令牌正确才能访问。
JWT令牌
json web token ,通信双方以json数据格式安全的传输信息
ThredLocal
ThreadLocal提供了一种局部线程变量的机制,使得每个线程都可以独立的改变自己的副本,而不会影响其他线程的副本。 ThredLocal是线程安全的。
ThredLocal工具类
package com.event.utils;
import java.util.HashMap;
import java.util.Map;
/**
* ThreadLocal 工具类
*/
@SuppressWarnings("all")
public class ThreadLocalUtil {
//提供ThreadLocal对象,
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
//根据键获取值
public static <T> T get(){
return (T) THREAD_LOCAL.get();
}
//存储键值对
public static void set(Object value){
THREAD_LOCAL.set(value);
}
//清除ThreadLocal 防止内存泄漏
public static void remove(){
THREAD_LOCAL.remove();
}
}
我们可以维护一个全局的ThreadLocal变量,在用户登录后在preHandler方法中,将用户的数据放入到set到该用户的ThreadLocal中,从而可以在需要时取出有用信息。
实体类校验
当参数传入的是常用数据类型时,我们可以通过public Result register(@Pattern(regexp="^\\S{5,16}$") String username, @Pattern(regexp="^\\S{5,16}$")String password){
来对传入参数进行校验。但是当传入的参数为实体类时,我们无法使用该方法啊。因此我们在实体类中添加注解进行校验:
@NotNull
private int id;
private String username;
//返回时忽略password,防止密码泄露
@JsonIgnore
private String password;
//不能为NULL,并且不能为空
@NotEmpty
@Pattern(regexp = "^\\S{1,10}$")
// 实体类验证,不能为空切,且长度在1-10之间
private String nickname;
同时需要在实体类参数处添加@Validated来注明类中使用注解来校验
参数校验另一种格式public Result updateAvatar(@RequestParam @URL String avatarUrl){
校验前端传递的参数是URL类型的,不是则会报错
自定义校验
有些情况下某些字段是我们自己定义的值,例如:
这个表中的state字段是一个String类型的,他的值只能为已发布|草稿,但是在Valitdated中没有这样的校验,我们可以通过自定义注解来实现
创建State注解
@Documented
@Constraint(
validatedBy = {StateValidation.class}
)
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface State {
String message() default "state的属性只能是草稿或者已发布";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
实现注解的校验条件
public class StateValidation implements ConstraintValidator<State,String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if(value == null){
return false;
}
if(value.equals("已发布")||value.equals("草稿")){
return true;
}
return false;
}
}
HTTP请求方式
- GET请求:GET请求通常用于从服务器检索数据。它不会改变服务器上的数据,因此被认为是安全的和幂等的。在实际应用中,GET请求常用于获取信息如查询操作。
- POST请求:POST请求通常用于向服务器发送数据,这些数据通常会导致服务器状态的改变,如创建新的记录或修改已有的资源。POST请求可以携带更多的数据,且不会将数据暴露在URL中,因此相对更安全
- PUT请求:PUT请求用于更新现有资源的全部信息。它会替换资源的当前状态,因此也是幂等的
- DELETE请求:DELETE请求用于删除指定的资源。在RESTful API设计中,DELETE请求通常用于删除某个具体的资源实例
Controller类中函数上的@RequestParam()注解
@RequestParam()是MVC中接受普通参数的注解,请求参数绑定到你控制器的方法参数上
语法:
@RequestParam(vaule="",requried="true/false",defaultValue="")
value:参数名
required:是否包含该参数,当为false时,sql语句要用到该参数时,需要使用动态SQl
defaultValue:默认参数值,如果设置了该值,required=true将失效,自动为false,如果没有传该参数,就使用默认值
动态sql
if标签:在前端传参中可能有些数据不是必须的,在某些时候有,某些时候没有,这就要用动态SQL来处理,通过if标签的test属性判断:
select # from user
where
<if test=" name != null">
name=#{name}
</if>
<if test="">-----</if>
但这种情况会出现问题,如果第一个是null的话,SQL会拼接成 where and 是一个错误语句
因此我们还可以添加上标签
select # from user
<where>
<if test=" name != null">
name=#{name}
</if>
<if test="">-----</if>
</where>
choose–when-otherwise:相当于switch–case-default
select # from user
<where>
<choose>
<when test=" name != null">
name=#{name}
</when>
<when test="">sql</when>
<otherwise>sql</otherwise>
</choose>
</where>
foreach:对于一些 SQL 语句中含有 in 条件,需要迭代条件集合来生成的情况,可以使用 foreach 来实现 SQL 条件的迭代。
Mybatis foreach 标签用于循环语句,它很好的支持了数据和 List、set 接口的集合,并对此提供遍历的功能。语法格式如下。
foreach 标签主要有以下属性,说明如下:
在这里插入图片描述
<foreach item="item" index="index" collection="list|array|map key" open="(" separator="," close=")">
#{item}
</foreach>
set: 在 Mybatis 中,update 语句可以使用 set 标签动态更新列。set 标签可以为 SQL 语句动态的添加 set 关键字,剔除追加到条件末尾多余的逗号。 代码如下。
<!--使用set元素动态修改一个网站记录 -->
<update id="updateWebsite">
UPDATE website
<set>
<if test="name!=null">name=#{name},</if>
<if test="url!=null">url=#{url},</if>
</set>
WHERE id=#{id}
</update>
item:表示集合中每一个元素进行迭代时的别名。
index:指定一个名字,表示在迭代过程中每次迭代到的位置。
open:表示该语句以什么开始(既然是 in 条件语句,所以必然以(开始)。
separator:表示在每次进行迭代之间以什么符号作为分隔符(既然是 in 条件语句,所以必然以,作为分隔符)。
close:表示该语句以什么结束(既然是 in 条件语句,所以必然以)开始)
trim: 在 MyBatis 中除了使用 if+where 实现多条件查询,还有一个更为灵活的元素 trim 能够替代之前的做法。
trim 一般用于去除 SQL 语句中多余的 AND 关键字、逗号,或者给 SQL 语句前拼接 where、set 等后缀,可用于选择性插入、更新、删除或者条件查询等操作。trim 语法格式如下。
<select id="selectUser" resultType="User">
SELECT id,name,url,age,country
FROM User
<trim prefix="where" prefixOverrides="and">
<if test="name != null and name !=''">
AND name LIKE CONCAT ('%',#{name},'%')
</if>
<if test="url!= null">
AND url like concat ('%',#{url},'%')
</if>
</trim>
</select>
分页使用PageHelper
在pom文件导入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
使用PageHelper时需要根据要求自定义返回类型,例
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean <T>{
private Long total;//总条数
private List<T> items;//当前页数据集合
}
在Service层调用PageHelper实现分页功能,首先要调用PageHelper.startPage(pageNum,pageSize);
来开启分页功能,通过数据库查询到数据返回时,在Service层实现分页
@Override
public PageBean<Article> getList(Integer pageNum, int pageSize, Integer categoryId, String state) {
PageBean<Article> pageBean = new PageBean<>();
//开启分页查询
PageHelper.startPage(pageNum,pageSize);
//调用Mapper
Map<String,Object> map=ThreadLocalUtil.get();
int id = (int)map.get("id");
List<Article> list = articleMapper.list(id,categoryId,state);
//PageHelper提供方法,可以获取pageHelper分页查询后的大奥的总记录数和当前页面数据
Page<Article> p = (Page<Article>) list;
//填充到pageBean对象中
pageBean.setTotal(p.getTotal());
pageBean.setItems(p.getResult());
return pageBean;
}
阿里云OSS
OSS(对象存储),我们将用户上传的头像存在在云
抽象出一个工具类,我们在使用时调用这个接口的uoLoad方法,传入文件的名字和流就可以实现上传到阿里云的OSS中。
public class AilOSS {
private final static String endpoint = "https://oss-cn-beijing.aliyuncs.com";
private final static String OSS_ACCESS_KEY_ID = "LTAI5tDbz8ysWcnZETkUBqxK";
private final static String OSS_ACCESS_KEY_SECRET ="Bz4K4y5Kw8I7et7xwcK97bpDxnROk4";
private final static String bucketName = "big-event-zxz";
public static String upLoad(String objectName,InputStream inputStream) throws Exception {
String url = "";
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
// String endpoint = "https://oss-cn-beijing.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
// EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// String OSS_ACCESS_KEY_ID = "LTAI5tDbz8ysWcnZETkUBqxK";
// String OSS_ACCESS_KEY_SECRET ="Bz4K4y5Kw8I7et7xwcK97bpDxnROk4";
// 填写Bucket名称,例如examplebucket。
// String bucketName = "big-event-zxz";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
// String objectName = "123.png";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
// String filePath= "D:\\javaFile\\123.jpg";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, OSS_ACCESS_KEY_ID,OSS_ACCESS_KEY_SECRET);
try {
// InputStream inputStream = new FileInputStream(filePath);
// 创建PutObjectRequest对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
// 创建PutObject请求。
PutObjectResult result = ossClient.putObject(putObjectRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
url = "https://"+bucketName+"."+endpoint.substring(endpoint.lastIndexOf("/")+1)+"/"+objectName;
// ;
return url;
}
}
使用
@RestController
public class FileController {
@PostMapping("/upload")
public Result<String> upload(MultipartFile file) throws Exception {
String originalFilename = file.getOriginalFilename();
//截取除了后缀的文件名修改为UUID 防止重复
String filename = UUID.randomUUID().toString()+originalFilename.substring(originalFilename.lastIndexOf("."));
// file.transferTo(new File("D:\\javaFile\\" + originalFilename));
String url = AilOSS.upLoad(filename,file.getInputStream());
return Result.success(url);
}
}
集成Redis
我们在修改密码的模块时,当我们修改密码之后我们的token并没有变化,我们仍然可以去访问其他的接口,这不是我们想要的效果,我们希望在修改密码之后,我们需要输入新密码登录之后才可以去访问其他的接口。我们使用redis存储我们的token,在修改密码后删除token。
首先我们在pom文件中引入Redis的stater
<!-- redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
然后在yml配置文件中配置redis的相关配置,我这里只配置了接口
data:
redis: localhost
port: 6379
在Redis启动之前会先初始化spring容器,redis是通过注入来获得一个操作redis的对象
@Autowired
private StringRedisTemplate stringRedisTemplate;
ValueOperations<String,String> operations= stringRedisTemplate.opsForValue();
operations.set(键,值,过期时间,时间单位)
修改密码后删除redis中的token
ValueOperations operations = stringRedisTemplate.opsForValue();
operations.getOperations().delete(token);//delete(键)
拦截器中检验token是否存在
ValueOperations<String,String> operations = stringRedisTemplate.opsForValue();
String redisToken = operations.get(token);
if(redisToken == null){//token失效
throw new RuntimeException();
}
SpringBoot项目部署
添加打包的配置类
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.1.3</version>
</plugin>
</plugins>
</build>
通过maven中的package打包
通过命令行的命令启动jar
SpringBoot配置方式
配置优先级
- 通过控台
- 通过配置系统环境变量
- 外部配置文件
通过在jar文件下创建一个application.yml文件实现 - 通过yml或properties文件
Vue
vue生命周期(8个阶段)
比较重要是mounted
Vue3项目创建
创建一个vue项目需要通过cmd下的命令来实现
在要创建vue的文件目录下通过npm init vue@latest
命令创建一个vue项目
输入项目名称
执行提示的命令
npm run dev
是运行vue项目
vue项目目录
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/2f375c94b3074a27be78f90525472eaa.png
其次,我们在使用vue项目时还需要引入一些其他的依赖例如lelement-plus、axios等
组合式API
响应式变量 const articleList = ref(10);
定义了一个响应式的变量
import { ref } from 'vue'
// 定义响应式数据 count 默认值是10
const count = ref(10);
import { ref } from 'vue'
const counter = ref(0)
const addCount = function(n) {
// 把count的值加上n
count.value += n;
}
我们需要通过ref.value去访问响应式变量
例
<script setup>
// 发送异步请求,现在项目中导入,使用npm install axios
import {articleGetAllArticle,articleSearchService} from '@/api/article.js'
const articleList = ref([]);
// 同步 async await 获取所有文章
const getAllArticle = async function(){
let data = await articleGetAllArticle();
articleList.value=data;
}
getAllArticle();
//定影响应数据
const searchConditions =ref(
{
category:'',
state:''
}
);
const search = async function(){
let data = await articleSearchService({...searchConditions});
articleList.value = data;
}
</script>
vue拦截器
import {ref} from 'vue';
//定义变量记录公共URl
const baseURL = 'http://localhost:8080';
const instance = axios.create({baseURL});
// 添加响应拦截器
instance.interceptors.response.use(
result=>{
return result.da
},
err=>{
alert('服务异常!');
return Promise.reject(err);//失败
}
)
//暴露给外界接口
export default instance;
// import {ref} from 'vue';
// 定义变量记录公共URl
// const baseURL = 'http://localhost:8080';
// const instance = axios.create({baseURL});
import request from'@/util/request.js'
// 同步等待服务器响应结果并返回,async,await
export function articleGetAllArticle(){
// return await axios.get('http://localhost:8080/article/getAll')
return request.get('article/getAll')
// .then(result=>{
// return result.data;
// }).catch(err=>{
// console.log(err);
// });
}
export function articleSearchService(conditions){
// return await axios.get('http://localhost:8080/article/search',{params:conditions})
return request.get('article/search',{params:conditions})
// .then(result=>{
// return result.data;
// }).catch(err=>{
// console.log(err);
// })
}