99-Spring

1. Mvc

1. 入参

1. integer

  • 前端可以传递String类型,被后端的integer类型的pojo来接收

2. 形参为List

L2l5T3Y5cWxyRi9MOExGR0tNRmpTTk9ENVJpR2xiTUU1cTNkcHIvUk53PT0=
@GetMapping("/getByIds")
public ResultUtil<User> getByIds(@RequestParam(required = false) List<String> ids) {
}



2. 上传资源无原因报错

  • 必须是multipartResolver感觉用到了依赖注入。id是固定的
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

3. 请求转发表单重复提交

  • 表单提交成功,转发到新的页面。可是地址栏没有变化。当你刷新页面的时候,又将表单提交了

2. Filter

  • Filter是JavaEE中Servlet规范的一个组件,位于包javax.servlet中,它可以在HTTP请求到达Servlet之前,被一个或多个Filter处理
  • Filter的这个特性在生产环境中有很广泛的应用。eg:修改请求和响应、防止xss攻击、包装二进制流使其可以多次读,等等
  • 实际工作中,我们都是使用SpringBoot进行业务开发,本文总结三种Filter用法,SpringBoot版本采用目前最新的v2.3.1.RELEASE

1. 编写Filter

  • 要编写Filter,只需要实现javax.servlet.Filter接口就可以
public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter");
        // 要继续处理请求,必须添加 filterChain.doFilter()
        filterChain.doFilter(servletRequest,servletResponse);
    }

}
  • Filter接口有三个方法:init(), doFilter(), destroy()
  • 其中doFilter()需要自己实现,其余两个是default的,可以不用实现
  • 注意:如果Filter要使请求继续被处理,就一定要调用filterChain.doFilter()

2. Filter被Spring管理

  • 让自定义的 Filter 被 Spring 的 IOC 容器管理,有三种实现方式,各有优缺点

1. @Component @Order

  • @Component + @Order 注解,即可被Spring管理。缺点是拦截所有URL,不能通过配置去拦截指定的URL
  • 有多个Filter时,@Order(1)注解会指定执行顺序,数字越小,越优先执行。只写@Order,默认顺序值是Integer.MAX_VALUE
@Component
@Order(1)
public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter");
        // 要继续处理请求,必须添加 filterChain.doFilter()
        filterChain.doFilter(servletRequest,servletResponse);
    }

}

2. @WebFilter @ServletComponentScan

  • @WebFilter注解,启动类@ServletComponentScan("com.listao.filter"),Filter所在包路径
  • @WebFilter + @ServletComponentScan支持对Filter匹配指定URL,不支持指定Filter的执行顺序
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("MyFilter");
        // 要继续处理请求,必须添加 filterChain.doFilter()
        filterChain.doFilter(servletRequest,servletResponse);
    }

}
 










@SpringBootApplication
@ServletComponentScan("com.listao.filter")
public class FilterDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(FilterDemoApplication.class, args);
    }

}

 







3. @Configuration

  • 每个自定义的Filter声明成Bean交给Spring管理即可,还可以设置匹配的URL、指定Filter的先后顺序
@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean registerMyFilter(){
        FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();
        bean.setOrder(1);
        bean.setFilter(new MyFilter());
        // 匹配 `/hello/` 下面的所有url
        bean.addUrlPatterns("/hello/*");
        return bean;
    }

    @Bean
    public FilterRegistrationBean registerMyAnotherFilter(){
        FilterRegistrationBean<MyAnotherFilter> bean = new FilterRegistrationBean<>();
        bean.setOrder(2);
        bean.setFilter(new MyAnotherFilter());
        // 匹配所有url
        bean.addUrlPatterns("/*");
        return bean;
    }

}





 
 
 

 














3. boot

1. 获取进程ID

// 1. 获取当前 SpringBoot 应用的进程号
ApplicationPid pid = new ApplicationPid();
System.out.printf("进程ID: %s%n", pid.toString());

// 2. 还可以通过 `ManagementFactory` 获取进程ID
String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
  • 可以通过在 META-INF/spring.factories 中注册监听器,将进程ID写入到一个文件中。通过配置 spring.pid.file 属性,指定文件路径
spring.pid.file=d:/app.pid

2. 应用运行主目录

// 访问应用程序主目录的方法。无论是 Jar 文件、解压文件还是直接运行的应用程序,都可以找到一个合理的主目录
// 在 IDE 中运行和打包成 Jar 后运行,输出的结果会有所不同
ApplicationHome home = new ApplicationHome();
System.out.printf("dir: %s, source: %s%n", home.getDir(), home.getSource());

3. 获取 Java 版本

// 获取当前运行的 Java 版本
// `JavaVersion` 是一个枚举类,定义了从 17 到 22 的版本,还可以进行版本比较
System.out.printf("Java Version: %s%n", JavaVersion.getJavaVersion());

4. 应用临时目录

  • 无论是在 IDE 下还是在 Jar 方式运行,Windows 平台下临时目录都位于 Temp 文件夹下
// 不同 Spring Boot 应用程序将获得不同的临时目录
ApplicationTemp temp = new ApplicationTemp();
System.out.printf("临时目录: %s%n", temp.getDir());

5. 系统属性/环境变量访问

  • SystemProperties 类可以方便地访问系统属性。如果属性不存在,它还会尝试从环境变量中获取
  • get 方法支持可变长参数,可以传递多个 key,获取时遍历遇到非 null 的直接返回
System.out.printf("java.home=%s%n", SystemProperties.get("java.home"));

6. 实例化对象

  • Instantiator 是一个简单工厂,可以通过注入可用参数来实例化对象
  • 可以方便地一次性实例化多个同类型的类
public interface DAO {}
public class A implements DAO {}
public class B implements DAO {}

Instantiator<DAO> instant = new Instantiator<>(DAO.class, p -> {});
List<DAO> ret = instant.instantiate(List.of("com.pack.A", "com.pack.B"));
System.out.printf("%s%n", ret);

7. 资源加载

  • 加载后的 List 可以注册到 Environment 中,在系统中直接访问
// 加载 .properties
PropertiesPropertySourceLoader propertyLoader = new PropertiesPropertySourceLoader();
List<PropertySource<?>> list = propertyLoader.load("pack", new ClassPathResource("pack.properties"));
System.out.printf("pack.*: %s%n", list.get(0).getSource());

// 加载 .xml、.yaml
YamlPropertySourceLoader yamlLoader = new YamlPropertySourceLoader();
List<PropertySource<?>> yamls = yamlLoader.load("pack", new ClassPathResource("pack.yml"));
System.out.printf("pack.*: %s%n", yamls.get(0).getSource());

8. 获取 basePackages

// 获取当前应用启动类所在的基包 `basePackages`
@Autowired
private ConfigurableApplicationContext context;

System.out.printf("basePackages: %s%n", AutoConfigurationPackages.get(context));