Spring Boot - 实用功能21 - 自定义启动器Starter

自定义启动器Starter


Starter相当于模块,它能将所需的依赖整合起来,并对模块内的Bean进行自动配置

功能类开发 -> 自动配置类 -> 测试工程开发 -> 拦截器进行功能完善 -> 添加配置项

一:功能类开发

输出客户端(IP区分)的访问次数

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version> <!-- 请根据需要选择合适的版本 -->
    <scope>provided</scope> <!-- 通常服务器已经提供该依赖 -->
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
package com.cui.ipcounterstarter.service.impl;

import com.cui.ipcounterstarter.service.IpCounterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 功能方法 - 统计IP的出现次数
 * @author cui haida
 * 2025/3/30
 */
@Service
public class IpCounterServiceImpl implements IpCounterService {

    @Autowired
    private HttpServletRequest request;

    // 统计次数
    private final Map<String, Integer> ipCountMap = new HashMap<>();

    @Override
    public void record() {
        // 获取当前访问的ip
        String ip = request.getRemoteAddr();
        // 统计次数,封装到Map
        Integer count = ipCountMap.get(ip);
        count = Objects.isNull(count) ? 1 : count + 1;
        ipCountMap.put(ip, count);

        System.out.println("ip:" + ip + ",count:" + count);
    }
}

二:自动配置类

将刚才的功能类进行实例化

package com.cui.ipcounterstarter.configure;

import com.cui.ipcounterstarter.service.IpCounterService;
import com.cui.ipcounterstarter.service.impl.IpCounterServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 自动配置类,实例化功能类
 * @author cui haida
 * 2025/3/30
 */
@Configuration
public class IpAutoConfiguration {
    @Bean
    public IpCounterService ipCounterService(){
        return new IpCounterServiceImpl();
    }
}

SpringBoot 2.7废止,SpringBoot 3 全面移除

META-INF -> spring.factories

SpringBoot 2.7+用这个

META-INF -> spring -> org.springframework.boot. autoconfigure.AutoConfiguration.imports

在这里插入图片描述

三:编写测试项目进行测试

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

<!-- 引入刚才写好的starter -->
<dependency>
    <groupId>com.cui</groupId>
    <artifactId>ipcounterstarter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

在这里插入图片描述

package com.cui.ipcountertest.controller;

import com.cui.ipcounterstarter.service.IpCounterService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author cui haida
 * 2025/3/30
 */
@RestController
public class testController {

    @Resource
    private IpCounterService ipCounterService;

    @GetMapping("/record")
    public void record(){
        ipCounterService.record();
    }
}

调用之后看到如下日志,说明基础功能实现完成

在这里插入图片描述

四:启动器中增加拦截器

为了避免在测试工程中手动书写注入,需要在启动器中增加拦截器保证自动运行

package com.cui.ipcounterstarter.interceptor;

import com.cui.ipcounterstarter.service.IpCounterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 拦截器
 * @author cui haida
 * 2025/3/30
 */
public class IpCountInterceptor implements HandlerInterceptor {

    @Autowired
    private IpCounterService ipCounterService;

    /**
     * 拦截器 - pre是在请求处理之前执行,如果返回false,则请求中断,如果返回true,执行下一个拦截器,如果无拦截器,执行controller
     * 将实现的功能放在这里,这样就不用再测试工程的controller中描述了
     * @param request 请求
     * @param response 响应
     * @param handler 处理器
     * @return 如果返回false,则请求中断,如果返回true,执行下一个拦截器
     * @throws Exception 异常
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        ipCounterService.record();
        return true;
    }
}

拦截器加入到Spring MVC中

package com.cui.ipcounterstarter.config;

import com.cui.ipcounterstarter.interceptor.IpCountInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author cui haida
 * 2025/3/30
 */
@Configuration
public class SpringMvcConfigure implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new IpCountInterceptor()).addPathPatterns("/**");
    }

    @Bean
    public IpCountInterceptor ipCountInterceptor() {
        return new IpCountInterceptor();
    }
}

此时测试工程将不再用手动引入bean和调用

五:配置文件设置

如果支持测试工程在配置文件进行个性化设置,可以在启动器工程规定好前缀,然后启动器工程编写对应的ipProperties

package com.cui.ipcounterstarter.property;

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

/**
 * 支持配置文件的修改
 * @author cui haida
 * 2025/3/30
 */
@Data
@Component
@ConfigurationProperties(prefix = "tools.ip") // 读取配置文件
public class IpCounterProperties {
    private String display = Display.SIMPLE.getValue();

    /**
     * 显示方式
     */
    public enum Display {
        SIMPLE("simple"),
        DETAIL("detail");

        private String value;

        Display(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }
}

响应的功能实现类也要修改

package com.cui.ipcounterstarter.service.impl;

import com.cui.ipcounterstarter.property.IpCounterProperties;
import com.cui.ipcounterstarter.service.IpCounterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 功能方法 - 统计IP的出现次数
 * @author cui haida
 * 2025/3/30
 */
@Component
public class IpCounterServiceImpl implements IpCounterService {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private IpCounterProperties properties;

    // 统计次数
    private final Map<String, Integer> ipCountMap = new HashMap<>();

    @Override
    public void record() {
        // 获取当前访问的ip
        String ip = request.getRemoteAddr();
        // 统计次数,封装到Map
        Integer count = ipCountMap.get(ip);
        count = Objects.isNull(count) ? 1 : count + 1;
        ipCountMap.put(ip, count);

        if (properties.getDisplay().equals(IpCounterProperties.Display.DETAIL.getValue())) {
            System.out.println("\t\t\tIP访问监控\t\t\t");
            System.out.println("+---------ip----------+--------count--------+");
            ipCountMap.forEach((key, value) -> {
                System.out.println("|\t\t" + key + "\t\t|\t\t" + value + "\t\t|");
            });
            System.out.println("+-------------------------------------------+");
        } else {
            ipCountMap.forEach((key, value) -> {
                System.out.println("ip: " + key + "\tcount: " + value);
            });
        }
    }
}

最后在测试工程的配置文件中设置对应的值即可

tools:
	ip:
		display: "detail"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值