常用技术整合Springboot快速开发

178 阅读5分钟

整合ElasticSearch

1,pom

<!--es 高级客户端-->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.12.1</version>
        </dependency>

<!--为了插入时转成json-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.72</version>
        </dependency>

2,config,因为使用的不是springboot提供的数据源,所以需要手动配置

@Configuration
public class ElasticSearchConfig {

    //请求参数
    public static final RequestOptions COMMON_OPTIONS;
    static {
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();

        COMMON_OPTIONS = builder.build();
    }

    //new HttpHost("地址",“端口”,"http") 连接地址
    //如果在集群环境下 需要配置多个
    @Bean
    public RestHighLevelClient esRestClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("192.168.41.33", 9200, "http"))
        );
        return client;
    }
}

es api的使用

//注入
    @Autowired
    private RestHighLevelClient client;


//创建索引 CreateIndexRequest("")

   //创建索引请求
        CreateIndexRequest createIndexRequest = new CreateIndexRequest("test_index");
        //客户端执行,请求后获得响应
        CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        System.out.println(createIndexRequest);


//获取索引 只能判断是否存在索引 GetIndexRequest("")
 GetIndexRequest getIndexRequest = new GetIndexRequest();
        boolean exists = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);


//删除索引 DeleteIndexRequest("")

        

整合Redis

一,导入pom依赖

   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
   </dependency>

二,配置application.yml

spring:
  redis:
    host: 172.17.52.104  #主机名
    port: 7001   #端口号
    database: 0  #第几号数据库

三,测试使用

    //注入StringRedisTemplate 或 redisTemplate
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

四,配置key序列化

@Configuration
public class RedisConfiguration {

        @Bean
        //不指定id的话bean 的id就是方法名
        //返回结果就是spring中管理的bean
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
                throws UnknownHostException {
            RedisTemplate<Object, Object> template = new RedisTemplate<>();

            //ObjectMapper 指定在转成json的时候的一些转换规则
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

            template.setConnectionFactory(redisConnectionFactory);
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            //把自定义objectMapper设置到jackson2JsonRedisSerializer中(可以不设置,使用默认规则)
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

            //RedisTemplate默认的序列化方式使用的是JDK的序列化
            //设置了key的序列化方式
            template.setKeySerializer(new StringRedisSerializer());
            //设置了value的序列化方式
            template.setValueSerializer(jackson2JsonRedisSerializer);
            return template;
        }

}

整合RabbitMQ

启动rabbitmq

#启动 systemctl start rabbitmq-server #重启 systemctl restart rabbitmq-server #停止 systemctl stop rabbitmq-server #查看状态 systemctl status rabbitmq-server

启动成功后 ip地址+15672访问

创建队列必须要有消费者,如果没有消费者的话那队列就

导入依赖

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

yml

spring: 
	 rabbitmq:
    	host: 192.168.141.124 #主机IP
    	port: 5672 #端口
    	username: root #用户名
    	password: root #密码

消息发送

##注入模板
@Autowired
private AmqpTemplate amqpTemplate;


##直接发送消息到队列
amqpTemplate.convertAndSend("队列名",消息)

##发送消息到交换机(订阅交换机)
amqpTemplate.convertAndSend("交换机名" ,"" ,消息)

##发送消息到交换机(路由交换机)
amqpTemplate.convertAndSend("交换机名" ,路由key ,消息)

RabbitMQ工作模式

消息通信是由两个角色完成:消息生产者(producer)和消息消费者(Consumer)

1,操作hello word 消息队列模式

//test helloword 发布消息
    @Test
    void helloword() {
        rabbitTemplate.convertAndSend("hello_word","helloWord-SPRING BOOT");
    }


//消费消息
@Component
public class HelloCustomer {
    @RabbitListener(queuesToDeclare = @Queue(value = "hello_word"))
    public void a(String msg){
        System.out.println("msg = " + msg);
    }
}

2,操作WorkQuene 工作模式

 //test work
    @Test
    public void work(){
        for (int i = 0; i < 10; i++) {
            rabbitTemplate.convertAndSend("work","hello work-springboot"+i);
        }
    }


//消费消息
@Component
public class WorkCustomer {

    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void  testWork(String msg){
        System.out.println("msg1 = " + msg);
    }


    @RabbitListener(queuesToDeclare = @Queue("work"))
    public void  testWork2(String msg){
        System.out.println("msg2 = " + msg);
    }
}

默认在 spring amqp 实现中 work这种方式就是公平调度,如果需要实现能者多劳需要额外配置

3,操作Fanout 发布订阅模式

//test fanout 广播模式
    @Test
    public void fanout(){
        rabbitTemplate.convertAndSend("logs","","fanout SPRINGBOOT");
    }


//消费消息
@Component
public class FanoutCustomer {

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue, //创建临时队列
                    exchange = @Exchange(value = "logs",type = "fanout")  //绑定交换机和类型
            )
    })
    public void test1(String msg){
        System.out.println("msg1 = " + msg);
    }
}

4,操作Direct 路由模式

 //test route 路由模式
    @Test
    public void testRoute(){
        rabbitTemplate.convertAndSend("directs","error","发送info给key的路由");
    }

@Component
public class DirectCustomer {

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "directs",type = "direct"),
                    key = {"info"}
            )
    })
    public void test(String msg){
        System.out.println("msg1 = " + msg);
    }
}

5,操作topic 动态路由

 //test topic 动态路由 订阅模式
    @Test
    public void testTopic(){
        rabbitTemplate.convertAndSend("topics","user.save","user.save");
    }

 
@Component
public class TopicCustomer {
    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "topics",type = "topic"),
                    key = {"user.save","user.*"}

            )
    })
    public void test(String msg){
        System.out.println("msg = " + msg);
    }

    @RabbitListener(bindings = {
            @QueueBinding(
                    value = @Queue,
                    exchange = @Exchange(value = "topics",type = "topic"),
                    key = {"user.*"}

            )
    })
    public void test2(String msg){
        System.out.println("msg = " + msg);
    }
}

整合swagger

集成

第一步,新建springboot项目

第二步,导入pom依赖

	    <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>

第三步,编写hello工程

第四步,启用swagger --> config

应用主类增加注解@EnableOpenApi,

@Configuration
@EnableOpenApi //开启swagger
public class SwaggerConfig {
    
}

第五步,

启动项目,访问地址:http://localhost:8080/swagger-ui/index.html

(注意:swagger2.x版本中访问的地址的为http://localhost:8080/swagger-ui.html)

配置

注释说明

@ApiModel("用户类") //标名实体类
@ApiModelProperty("用户") //标名实体类里的字段	
@ApiOperation("用户controller") //标名controller请求方法

整合JWT

什么是JWT

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT的构成

第一部分我们称它为头部(header),

第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),

第三部分是签证(signature).

使用

第一步,导入pom.xml

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.12.0</version>
</dependency>

第二步,编写使用工具类

生成jwt

 //自定义签名密钥
    private static final String SIGN = "!q@w#e$r%t^y&u*i(ou185@qq.com)!@#";

    /**
     * 生成token header.payload.sign
     */

    public static String getToken(Map<String,String> map){
        //定义令牌过期时间
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DATE, 7); //七天过期

        JWTCreator.Builder builder = JWT.create();

        //payload
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });

        //设定令牌过期时间
        String token = builder.withExpiresAt(instance.getTime())
                //sign
                .sign(Algorithm.HMAC256(SIGN));

        return token;
    }

验证token

/**
     * 验证token合法性
     * @param token
     */
    public static DecodedJWT varify(String token){
        return JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
    }

使用好封装后的工具类后,可以生成token,并根据token对访问请求的控制,但是在每一个请求都做token验证太麻烦,所以可以添加我们的拦截器 interceptors 实现 HandlerInterceptorpreHandle方法

public class JWTInterceptors implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        //获取请求头之内的令牌
        String token = request.getHeader("token");

        try {
            DecodedJWT varify = JWTUtil.varify(token);
            return true; //放行请求
        } catch (SignatureVerificationException e){
            e.printStackTrace();
            map.put("msg","无效签名!");
        }catch (TokenExpiredException e){
            e.printStackTrace();
            map.put("msg","token过期");
        }catch (AlgorithmMismatchException e){
            e.printStackTrace();
            map.put("msg","token算法不一致!");
        }
        catch(Exception e) {
            e.printStackTrace();
            map.put("msg","token无效!!!");
        }
        map.put("state",false); //设置状态
        //将map专为json
        String json = new ObjectMapper().writeValueAsString(map);
        //设置响应格式
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}

设好拦截器后,再配置相关的请求控制

@Configuration
public class InterceptorConfg implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptors()) //添加拦截器
                .addPathPatterns("/**")   //其他请求都拦截
                .excludePathPatterns("/user/**"); // 含/user请求不拦截
    }
}

整合Shiro

第一步,导入pom.xml

  	<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>

三大核心对象

  • Subject

    安全校验中,最常⻅的问题是"当前⽤户是谁?" "当前⽤户是否有权做x事?",所以考虑安全校验过程最⾃然的⽅式就是基于当前⽤户。Subject 代表了当前“⽤户”,应⽤代码直接交互的对象是 Subject,只要得到Subject对象⻢上可以做绝⼤多数的shiro操作。也就是说 Shiro 的对外API 核⼼就是 Subject。Subject 会将所有交互都会委托给 SecurityManager。 = = Subject是安全管理中直接操作的对象==

  • SecurityManager

    安全管理器;即所有与安全有关的操作都会与SecurityManager 交互;且其管理着所有 Subject;它是 Shiro的核⼼,它负责与 Shiro 的其他组件进⾏交互,它相当于 SpringMVC 中DispatcherServlet 的⻆⾊

  • Realm

    Shiro 从 Realm 获取安全数据(如⽤户、⻆⾊、权限),就是说SecurityManager 要验证⽤户身份,那么它需要从 Realm 获取相应的⽤户进⾏⽐较以确定⽤户身份是否合法; 也需要从 Realm 得到⽤户相应的⻆⾊/权限进⾏验证⽤户是否能进⾏操作; 可以把 Realm 看成 DAO,( 数据访问⼊⼝ )

配置三大核心对象

1,定义Realm 继承 AuthorizingRealm 实现方法

public class MyRealm extends AuthorizingRealm {

   //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了 => 授权");
        return null;//抛出异常
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了 => 认证");
           return null;  //抛出异常
     
    }
}

2,创建配置类 实现三大核心对象

@Configuration
public class ShiroConfiguration {

    //shiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

        /*
         anon:无需认证就可以访问
         authc:必须认证了才能让访问
         user:必须拥有 记住我 功能才能用
         perms:拥有对某个资源的权限才能访问
         role:拥有某个角色权限才能访问
         */
                //添加shiro内置过滤器
        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/add","anon");
        filterMap.put("/update","authc");
        filterMap.put("/login","anon");

//        filterMap.put("/*","authc");

        bean.setFilterChainDefinitionMap(filterMap);

        return bean;
    }

    //DafaultWebSecurityManager
    @Bean("SecurityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("getMyRealm") MyRealm myRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联 Realm
        securityManager.setRealm(myRealm);

        return securityManager;
    }


    //创建realm对象  需要自定义
    @Bean
    public MyRealm getMyRealm(){
        return new MyRealm();
    }


}

开始使用,在请求方法中的操作

 @RequestMapping("/login")
    public String login(String username,String password,Model model){
        System.out.println("username = " + username);
        System.out.println("password = " + password);
        //获得当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的登入数据
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);

        try {
            subject.login(token); //执行登入方法
            return "index";
        } catch (UnknownAccountException e) { //用户名不存在
            model.addAttribute("msg","用户名错误");
            return "login";
        } catch (IncorrectCredentialsException e){ //密码不存在
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }

整合JSP

pom.xml

<!--    web-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--    整合jsp-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>

    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-jasper</artifactId>
    </dependency>

    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>jsp-api</artifactId>
      <version>6.0.29</version>
    </dependency>

    <!--    JSTL-->
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

配置 resources / application.yml

#端口
server:
  port: 9090
#页面解析器
spring:
  mvc:
    view:
      prefix: /
      suffix: .jsp

接下来步骤就回归正常了

整合MyBatis

1,pom.xml

<parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.3.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

<!--mybatis整合springboot-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
<!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

2 resource / application

#连接数据库配置
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/数据库名?serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 1234
#数据库配置
mybatis:
  #配置mapper扫描路径
  mapper-locations: mapper文件的路径
  #配置实体类型别名
#  type-aliases-package:
 #配置输入sql的日志
logging:
  level:
  #com.ou.dao 持久层包名
    com.ou.dao: debug 

3,编写正常的数据持久层

4,最后创建启动类时注意加入MapperScan 扫描持久层的接口

@SpringBootApplication
@MapperScan("路径")
public class application {
    public static void main(String[] args) {
        SpringApplication.run(application.class,args);
    }
}

整合MyBatis-Publs

1,pom.xml

       <dependency>
     		<groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</version>
        </dependency>

		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>

2,application.yml

#数据库
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_plus?serverTimezone=GMT%2B8&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 1234

3,编写实现类,dao层接口继承BaseMapper

4,整合日志

#配置日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

5,最后创建启动类时注意加入MapperScan 扫描持久层的接口

整合HTML

Spring Boot可以结合Thymeleaf模版来整合HTML,使用原生的HTML作为视图。

Thymeleaf模版是面向Web和独立环境的Java模版引擎,能够处理HTML、XML、JavaScript、css

开始使用

使用maven创建boot项目 在 pom.xml导入Thymeleaf模板

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
  </dependency>

2,配置相关文件 application.yml中 与jsp类似

spring:
  thymeleaf:
	#前缀
    prefix: classpath:/templates/
	#后缀
    suffix: .html
	#模板
    mode: HTML5
	#编码
    encoding: UTF-8

3,编写controller向页面传数据 基本与 jsp一致 model

如果希望客户端可以直接访问HTML资源,将这些资源放置在static路径下即可,否则必须通过Handler的后台

映射才可以访问静态资源。

常用标签

赋值与拼接

赋值
<p th:text="${后端传递的值}"></p>

拼接“”中套‘’
<p th:text="'开始拼接'+${后端传递的值}"></p>
套上||
<p th:text="|始拼接,${后端传递的值}|"></p>

条件判断 if/unless

th:if 表示条件成立时显示内容,

th:unless 表示条件不成立时显示内容

<p th:if="${后端传递的值 == true}" th:text="显示"></p>
<p th:unless="${后端传递的值 != true}" th:text="不显示"></p>

循环

<tr th:each="定义的名字,定义引索名字:${后端传递的集合}">
       			<td th:text="${定义引索名字.index}"></td>  从0开始
                <td th:text="${定义引索名字.count}"></td>	 从1开始
                <td th:text="${定义的名字.属性}"></td>
                <td th:text="${定义的名字.属性}"></td>
            </tr>

stat是状态变量,属性: index 集合中元素的index (从0开始)

​ count 集合中元素的count (从1开始)

​ size 集合的大小

​ current 当前迭代变量

​ even/odd 当前迭代是否为偶数/奇数(从0开始计算)

​ first 当前迭代的元素是否是第一个

​ last 当前迭代的元素是否是最后一个

url

Thymeleaf对于URL的处理是通过@{...}进行处理,结合th:hrefth:src

文件上传

1,前后端不分离的情况下

导入commons-fileupload 工具包

    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>

1,文件上传

​ 定义:用户将自己本地计算机中文件上传到当前请求应用的应用服务器过程称之为文件上传

2,在springmvc 中 件上传注意事项

​ a.准备文件上传页面﹐表单提交方式必须是post enctype 必须为multipart/form-data

​ b.开发控制器在控制器中使用MultipartFile形式进行接收用户上传文件multipartResolver

​ d.multipartResolver在处理文件上传时要求项目中必须引入conmons-fileupload

​ c.使用wultipartPile方式接收文件必须在配置文件中配置文件上传解析器且解析器id必须

3,springboot中文件上传

​ 1,准备上传页面―提供form表单 提交post enctype:multipart/form-dato ​ 2.开发控制器使用 **MultipartFile ** 形式接收﹐将接收文件放入执行目录中即可

4,封装好工具类

/**
 * 处理图片的工具类
 */
public class PicUtil {

    public static String ForProcessing(MultipartFile f, HttpServletRequest request,String savePath) throws IOException {
        System.out.println("文件名:"+f.getOriginalFilename());
        System.out.println("文件类型:"+f.getContentType());
        System.out.println("文件大小:"+f.getSize());

        //UUID进行格式化准备入库
        String newFileNamePrefix = UUID.randomUUID().toString().replace("-","");
        //获取文件的后缀
        String extension = FilenameUtils.getExtension(f.getOriginalFilename());
        //进行拼接
        String newFileName = newFileNamePrefix+"."+extension;
        System.out.println("格式化后加了后缀名:"+newFileName);
        
        //获取存储位置 根据相对路径获取绝对路径
        String files = request.getSession().getServletContext().getRealPath(savePath);
        System.out.println("路径:"+files);

        //处理上传操作 找到一个输出位置files,写入文件名newFileName
        f.transferTo(new File(files,newFileName));
        return newFileName;

    }
}

5,设置上传时的文件 单个文件的最大值上传文件总的最大值

servlet:
    multipart:
      enabled: true
        # 单个文件的最大值
      max-file-size: 10MB
       #上传文件总的最大值
      max-request-size: 100MB

6,最后调用工具类传值就好

2,前后端分离 vue+springboot

前后端分离的情况下,必须配置虚拟路径才能让前端访问到本地的文件

新建个类 标注上@Configuration

@Configuration
public class FileHandleConfig implements WebMvcConfigurer {

	//保存到本地的路径
    private String uploadUrl = "E:\\IdeaProject\\elbSys\\elb\\src\\main\\resources\\static\\image\\";

    //前端访问的路径 http:xxx/upload/image/xxxx.jpg
    private String mappingUrl = "/upload/image";


    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        /*
         * 说明:增加虚拟路径(经过本人测试:在此处配置的虚拟路径,用springboot内置的tomcat时有效,
         * 用外部的tomcat也有效;所以用到外部的tomcat时不需在tomcat/config下的相应文件配置虚拟路径了,阿里云linux也没问题)
         */
        registry.addResourceHandler(mappingUrl+"/**").addResourceLocations("file:"+ uploadUrl + File.separator);
        //阿里云(映射路径去除盘符)
        //registry.addResourceHandler("/ueditor/image/**").addResourceLocations("/upload/image/");
        super.addResourceHandlers(registry);
    }
}

图片上传工具类 (自行更改)

public class ImgUploadUtil {

    static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");


   static private String filePath ="E:\\IdeaProject\\elbSys\\elb\\src\\main\\resources\\static\\image\\";

    public static TindexBanner ForProcessing(MultipartFile file) throws Exception {

        // 获取上传的文件名称
        String fileName = file.getOriginalFilename();
        // 得到格式化后的日期
        String format = sdf.format(new Date());
        System.out.println("文件名:" + file.getOriginalFilename());
        System.out.println("文件类型:" + file.getContentType());
        System.out.println("文件大小:" + file.getSize());

        String bannerName = fileName.substring(0, fileName.lastIndexOf("."));
        //UUID进行格式化准备入库
        String newFileNamePrefix = UUID.randomUUID().toString().replace("-", "");
        //获取文件的后缀
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        //进行拼接
        String newFileName = newFileNamePrefix + "." + extension;
        System.out.println("格式化后加了后缀名:" + newFileName);
        //当前服务器地址 写入数据库
        String httpPathImg = "http://localhost:9999"+"/upload/image/"+newFileName;



        // 得到文件保存的位置以及新文件名
        File dest = new File(filePath + newFileName);
        System.out.println(filePath);
        try {
            // 上传的文件被保存了
            file.transferTo(dest);

        }catch (IOException e) {
            System.out.println("失败");
        }

        return new TindexBanner(1,bannerName,httpPathImg,extension,new Date());
    }

}

3,图片上传千牛服务器

第一步,依赖导入

        <dependency>
            <groupId>com.qiniu</groupId>
            <artifactId>qiniu-java-sdk</artifactId>
            <version>7.2.29</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.72</version>
        </dependency>

        <dependency>
            <groupId>com.qiniu</groupId>
            <artifactId>happy-dns-java</artifactId>
            <version>0.1.4</version>
        </dependency>

        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

第二步,yml配置密钥,可前往千牛控制台查看 portal.qiniu.com/create

qiniu: 
  path: http://qn7mkdlff.hn-bkt.clouddn.com  #访问地址
  access-key: v9nWcMXbEQaYm2blpoQFbROwe9hemOyWRdaXpEgt  #密钥
  secret-key: Y8GisQ3T4sTKJEm-in_c9LkpKfOh14ZyBavPw37_  #加密密钥
  bucket: oublogimg  #空间命名

第三步,获取配置的密钥

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Data
@Component
public class QiniuyunData {
    /**
     * 密钥
     */
    @Value("${qiniu.access-key}")
    private String accessKey;
    /**
     * 加密密钥
     */
    @Value("${qiniu.secret-key}")
    private String secretKey;
    /**
     * 空间名
     */
    @Value("${qiniu.bucket}")
    private String bucket;
    /**
     * 访问地址
     */
    @Value("${qiniu.path}")
    private String path;
}

第四步,通过获取的密钥来拿到上传凭证 token

import com.qiniu.util.Auth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class QiniuUploadToken {

    @Autowired
    private QiniuyunData qiniu;
    
    /**
     * 获取七牛云Token
     */
    public  String getToken(){
        Auth auth = Auth.create(qiniu.getAccessKey(), qiniu.getSecretKey());
       return  auth.uploadToken(qiniu.getBucket());
    }
}

第五步,开始接收图片并上传

import com.alibaba.fastjson.JSON;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.UUID;

@Component
public class QiniuyunStartUploadUtil {

    //图片保存路径
    @Value("${image.save_path}")
    private String savePath;

    @Autowired
    private QiniuyunData qiniuyunData;

     /**
     * 
     * @param file       实体MultipartFile文件
     * @param QiniuToken  七牛的上传凭证
     * @return 返回数据库存储的地址 七牛地址+图片吗格式化后名
     * @throws Exception
     */
    public String ForProcessing(MultipartFile file, String QiniuToken) throws Exception {
        // 获取上传的文件名称
        String fileName = file.getOriginalFilename();
        System.out.println("上传地址: " + savePath);
        System.out.println("文件名:" + file.getOriginalFilename());
        System.out.println("文件类型:" + file.getContentType());
        System.out.println("文件大小:" + file.getSize());

        String bannerName = fileName.substring(0, fileName.lastIndexOf("."));
        //UUID进行格式化准备入库
        String newFileNamePrefix = UUID.randomUUID().toString().replace("-", "");
        //获取文件的后缀
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        //进行拼接
        String newFileName = newFileNamePrefix + "." + extension;
        System.out.println("格式化后加了后缀名:" + newFileName);
        String QiniuPath = savePath + newFileName;
        // 得到文件保存的位置以及新文件名
        File dest = new File(QiniuPath);

        String getUrl = null;
        try {
            // 上传的文件被保存了
            file.transferTo(dest);
            FileInputStream fileInputStream = new FileInputStream(dest);

            /**
             * 开始上传七牛云
             */
            UploadManager uploadManager = new UploadManager(new Configuration(Region.region2()));

            Response response = uploadManager.put(IOUtils.toByteArray(fileInputStream), newFileName,QiniuToken);

            DefaultPutRet putRet = JSON.parseObject(response.bodyString(), DefaultPutRet.class);

            HashMap<String, Object> map = new HashMap<>();
            map.put("key",putRet.key);
            map.put("hash",putRet.hash);
            System.out.println("map = " + map);

            /**
             * 访问地址拼接
             */
            getUrl = qiniuyunData.getPath()+"/"+newFileName;

        }catch (IOException e) {
            System.out.println("失败");
        }

        return getUrl;
    }

}

4,图片上传阿里云服务器

方式1

1,导入依赖

 <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.10.2</version>
        </dependency>

2,application.yml

aliyun:
    oss:
      endpoint: oss-cn-beijing.aliyuncs.com
      accessKeyId: LTAI4G2x9SDFqPcQvCPcecUX
      accessKeySecret: c8Ovt0fWZo1QvEsmyCxjU6kuRXxwAd
      bucketName: img-ou-reps
spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 100MB

3,创建AliossConfig配置文件

  @Value("${aliyun.oss.endpoint}")
    private  String endpoint;
    @Value("${aliyun.oss.accessKeyId}")
    private String KeyId;
    @Value("${aliyun.oss.accessKeySecret}")
    private String KeySecret;
    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     *
     * @param fileName 文件名
     * @return 文件的contentType
     */
    public String getContentType(String fileName) {
        String FilenameExtension = fileName.substring(fileName.lastIndexOf("."));
        System.out.println("=============>"+FilenameExtension);
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "application/x-bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg")||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }

        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xla") ||
                FilenameExtension.equalsIgnoreCase(".xlc")||
                FilenameExtension.equalsIgnoreCase(".xlm")||
                FilenameExtension.equalsIgnoreCase(".xls")||
                FilenameExtension.equalsIgnoreCase(".xlt")||
                FilenameExtension.equalsIgnoreCase(".xlw")) {
            return "application/vnd.ms-excel";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        if (FilenameExtension.equalsIgnoreCase(".pdf")) {
            return "application/pdf";
        }
        if (FilenameExtension.equalsIgnoreCase(".zip")) {
            return "application/zip";
        }
        if (FilenameExtension.equalsIgnoreCase(".tar")) {
            return "application/x-tar";
        }
        if (FilenameExtension.equalsIgnoreCase(".avi")) {
            return "video/avi";
        }
        if (FilenameExtension.equalsIgnoreCase(".mp4")) {
            return "video/mpeg4";
        }
        if (FilenameExtension.equalsIgnoreCase(".mp3")) {
            return "audio/mp3";
        }
        if (FilenameExtension.equalsIgnoreCase(".mp2")) {
            return "audio/mp2";
        }
        return "application/octet-stream";
    }

4,文件上传工具类

 @Autowired
    private AliConfig aliConfig;


    public  String ForProcessing(MultipartFile f) throws IOException {
        InputStream inputStream = f.getInputStream();

        //UUID进行格式化准备入库
        String newFileNamePrefix = UUID.randomUUID().toString().replace("-","");
        //获取文件的后缀
        String extension = FilenameUtils.getExtension(f.getOriginalFilename());
        //进行拼接
        String newFileName = newFileNamePrefix+"."+extension;
        System.out.println("格式化后加了后缀名:"+newFileName);
        
        OSS ossClient = new OSSClientBuilder().build(aliConfig.getEndpoint(),aliConfig.getKeyId(),aliConfig.getKeySecret());

        //设置权限及ContentType
        ObjectMetadata metadata = new ObjectMetadata();
        //设置权限
        metadata.setObjectAcl(CannedAccessControlList.PublicRead);
        //设置文件类型
        metadata.setContentType(aliConfig.getContentType(f.getOriginalFilename()));

        ossClient.putObject(aliConfig.getBucketName(),newFileName,inputStream,metadata);

        ossClient.shutdown();

        String url = "https://"+aliConfig.getBucketName()+"."+aliConfig.getEndpoint()+"/"+newFileName;
        
        return url;
    }

5,创建controller

 @PostMapping("/up")
    public void up(@RequestParam("file") MultipartFile multipartFile){
        System.out.println("multipartFile = " + multipartFile);
        try {
            String s = imgUp.ForProcessing(multipartFile);
            System.out.println("s = " + s);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

方式2

1,导入pom.xml

 <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>

2,yml配置

spring: 
	cloud: 
		alicloud:
      	access-key: LTAI4G2x9SDFqPcQvCPcecUX
      	secret-key: c8Ovt0fWZo1QvEsmyCxjU6kuRXxwAd
      	oss:
          	endpoint: oss-cn-beijing.aliyuncs.com

3,注入OSSClient

 @Autowired
   private OSSClient ossClient;

4,开始上传

//图片流地址
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\root\\Pictures\\wallhaven-0wwl6q_1920x1080.png");
//参数1:存储空间名
//参数2:图片名
//参数3:流
ossClient.putObject(v1,v2,v3 );

//关闭资源
ossClient.shutdown();
        
System.out.println(" ok " );