欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

现有web系统替换成Spring Boot2框架 之21 同时支持带项目名和不带项目名访问,web访问强制https,接口保持http访问 Spring Boot2带项目名不带项目名httpshttp 

程序员文章站 2022-03-04 18:06:16
...

由于历史原因项目需要同时支持带项目名访问和不带项目名访问,并且web访问需要强制转换成https,但是原有接口是http,需要同时支持。使用了现有方法和自己在过滤器中实现的部分逻辑完成

1. 配置文件application.properties

 

#https port
server.port=8443
#http port
server.http.port=8080
#是否启用https,代码中也用到此配置作为判断依据
server.ssl.enabled=true
#SSL证书路径,如果证书是打包在resource路径下的写classpath:xxxx.jks
server.ssl.key-store=/usr/local/work/smallbss/config/baicells.cloudapp.net.jks
server.ssl.key-store-password=1pcs4f7r78h
server.ssl.key-store-type=JKS
#项目路径默认设置成不带项目名
server.servlet.context-path=/

 

 配置中server.port=8443是https使用的端口,server.http.port=8080是http使用的端口。

项目路径默认设置成不带项目名是为了用户使用项目名访问时可以在过滤器中处理url,如果默认带项目名,再使用不带项目名访问就进不了过滤器,无法自己增加处理逻辑。此处将项目名去掉后还遇到了一些琐碎的问题,需要慢慢处理。

 

 

2. 配置过滤器和支持同时支持http和https访问:

 

import javax.servlet.DispatcherType;

import org.apache.catalina.connector.Connector;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class SystemWebMvcConfig  implements WebMvcConfigurer {

	@Value("${server.http.port}")
    private int serverHttpPort;
	
	/**
	 * 支持http和https同时访问
	 * @return
	 * 
	 */
	@Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
        return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {

            @Override
            public void customize(ConfigurableWebServerFactory factory) {
                if (factory instanceof TomcatServletWebServerFactory) {
                    TomcatServletWebServerFactory webServerFactory = (TomcatServletWebServerFactory)factory;
                    Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
                    // 设置http访问的端口号,不能与https端口重复,否则会报端口被占用的错误
                    connector.setPort(serverHttpPort);
                    webServerFactory.addAdditionalTomcatConnectors(connector);
                }
            }
        };
    }
	
	/**
	 * 添加过滤器
	 * @return
	 * 
	 */
	@Bean
    public FilterRegistrationBean<DelegatingFilterProxy> testFilterRegistration() {

        FilterRegistrationBean<DelegatingFilterProxy> registration = new FilterRegistrationBean<DelegatingFilterProxy>();
        registration.setFilter(new DelegatingFilterProxy("cloudFilter"));
        registration.addUrlPatterns("/*");
        registration.addInitParameter("paramName", "paramValue");
        registration.setEnabled(true);
        registration.setDispatcherTypes(DispatcherType.REQUEST);
        registration.setOrder(1);
        return registration;
    }
    
    @Bean(name="cloudFilter")
    public cloudFilter createBssFilter() {
        return new cloudFilter();
    }
    
}

 WebServerFactoryCustomizer()是设置http和https同时支持,原有接口调用http,web访问也可以用http,强制跳转到https在下边过滤器中实现。

3. 过滤器实现强制转换https和项目名转换

 

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;

import org.springframework.beans.factory.annotation.Value;

public class cloudFilter implements Filter {
	private static Logger logger = Logger.getLogger(cloudFilter.class);
    
	 //配置文件中配置的项目名
	 @Value("${server.servlet.context-path}")
	 private String context_path;
	 
	 //https的访问端口
	 @Value("${server.port}")
	 private int https_port;
	 
	 //https的访问端口
	 @Value("${server.http.port}")
	 private int http_port;
	 
	 //是否启用SSL
	 @Value("${server.ssl.enabled}")
	 private boolean server_ssl_enabled;

   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
           throws IOException, ServletException {
   	
       HttpServletRequest httpRequest = (HttpServletRequest) request;
       HttpServletResponse httpResponse = (HttpServletResponse) response;
       String path = httpRequest.getRequestURI();
       
       //访问首页即登陆时,如果启用ssl需要强制转换成https,并且处理项目名,支持带项目名和不带项目名同时访问
      	if("/mywebobject".equals(path) || "/mywebobject/".equals(path) || "/".equals(path)) {
      		String scheme = httpRequest.getScheme();
      		int port = http_port;
            logger.info("==============httpRequest.getRequestURL()=============="+httpRequest.getRequestURL());
            if(!context_path.replace("/", "").equals(path.replace("/", "")) || (server_ssl_enabled && !"https".equals(scheme))) {
            	URI reqUri = null;
          		try {
                    //启用SSL之后,登录页如果是http访问强制转换成https
          			if(server_ssl_enabled) {
                  	   scheme = "https";
                  	   port = https_port;
                     }
          			if(httpRequest.getQueryString()!=null && !"".equals(httpRequest.getQueryString())){
          				reqUri = new URI(httpRequest.getRequestURL()+"?"+httpRequest.getQueryString());
          			}else{
          				reqUri = new URI(httpRequest.getRequestURL().toString());
          			}
          			
          			//生成新的的跳转路径,注意端口和请求协议
              		URI newUri = new URI(scheme, reqUri.getUserInfo(),
          	                reqUri.getHost(), port, context_path,
          	                reqUri.getQuery(), reqUri.getFragment());
              		logger.info("=============new uri========"+newUri);
              		httpResponse.sendRedirect(newUri.toString());
              		return;
          		}catch(URISyntaxException e) {
          			logger.error(e.getMessage(),e);
          		}
            }
      	} else if (path.startsWith("/mywebobject")) {
      	//由于系统去掉默认项目名,接口访问时为了不需要客户端修改,再这将接口中的项目名去掉,转换成配置文件中的项目名
      		logger.info("=============path========"+path);
           	path = path.replaceFirst("/mywebobject", context_path).replace("//", "/");
           	logger.info("=============new path========"+path);
           	httpRequest.getRequestDispatcher(path).forward(request, response);
           	return;
      	}
      	chain.doFilter(request, response);//执行请求
      	return;
   }
}

 通过上边的过滤器处理,就实现了浏览器访问web将http强制转换成https,接口调用还是使用http。并且将带项目名的url处理成不带项目名。直接将项目名配置成“/”原代码可能会遇到一些问题需要根据实际情况来处理