Spring Boot 内置Tomcat——集成PHP解决方案

Posted Starzkg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot 内置Tomcat——集成PHP解决方案相关的知识,希望对你有一定的参考价值。

Demo:https://gitee.com/shentuzhigang/mini-project/tree/master/springboot-embed-tomcat-php-demo

问题分析

一、安装PHP

PHP安装与配置:https://www.php.net/manual/zh/install.php

二、Spring Boot 自定义Servlet容器

WebServerFactoryCustomizer:https://blog.csdn.net/qq_45235291/article/details/95921083

    @Bean
    public WebServerFactoryCustomizer webServerFactoryCustomizer() {
        return new WebServerFactoryCustomizer<TomcatServletWebServerFactory>() {
            @Override
            public void customize(TomcatServletWebServerFactory factory) {
                factory.setPort(8090);
            }
        };
    }

底层原理:

org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory

三、Spring Boot配置JSP

org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory

	protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
		...
		if (shouldRegisterJspServlet()) {
			addJspServlet(context);
			addJasperInitializer(context);
		}
		...
	}
	private void addJspServlet(Context context) {
		Wrapper jspServlet = context.createWrapper();
		jspServlet.setName("jsp");
		jspServlet.setServletClass(getJsp().getClassName());
		jspServlet.addInitParameter("fork", "false");
		getJsp().getInitParameters().forEach(jspServlet::addInitParameter);
		jspServlet.setLoadOnStartup(3);
		context.addChild(jspServlet);
		context.addServletMappingDecoded("*.jsp", "jsp");
		context.addServletMappingDecoded("*.jspx", "jsp");
	}

	private void addJasperInitializer(TomcatEmbeddedContext context) {
		try {
			ServletContainerInitializer initializer = (ServletContainerInitializer) ClassUtils
					.forName("org.apache.jasper.servlet.JasperInitializer", null).newInstance();
			context.addServletContainerInitializer(initializer, null);
		}
		catch (Exception ex) {
			// Probably not Tomcat 8
		}
	}

解决方案

方法一:通过org.apache.catalina.servlets.CGIServlet实现

根据Spring Boot中JSP的配置PHP和普通Tomcat服务器配置PHP的方式编写对Spring Boot 内置Tomcat的自定义配置

package io.shentuzhigang.demo.php.config;

import org.apache.catalina.Wrapper;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.Jsp;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @author ShenTuZhiGang
 * @version 1.1.0
 * @date 2020-11-02 22:42
 */
@Configuration
public class CustomTomcatConfig {
    @Bean
    public WebServerFactoryCustomizer webServerFactoryCustomizer() {
        return (WebServerFactoryCustomizer<TomcatServletWebServerFactory>) factory ->
                factory.addContextCustomizers(context -> {
                    Jsp jsp = new Jsp();
                    jsp.setClassName("org.apache.catalina.servlets.DefaultServlet");
                    Wrapper jspServlet = context.createWrapper();
                    jspServlet.setName("jsp");
                    jspServlet.setServletClass(jsp.getClassName());
                    jspServlet.addInitParameter("fork", "false");
                    jsp.getInitParameters().forEach(jspServlet::addInitParameter);
                    jspServlet.setLoadOnStartup(3);
                    context.addChild(jspServlet);
                    context.addServletMappingDecoded("*.jsp", "jsp");
                    context.addServletMappingDecoded("*.jspx", "jsp");
                    context.setPrivileged(true);

                    Php php = new Php();
                    php.setClassName("org.apache.catalina.servlets.CGIServlet");
                    Wrapper phpServlet = context.createWrapper();
                    phpServlet.setName("php");

                    phpServlet.setServletClass(php.getClassName());
                    phpServlet.addInitParameter("fork", "false");
                    php.getInitParameters().forEach(phpServlet::addInitParameter);
                    phpServlet.setLoadOnStartup(4);
                    context.addChild(phpServlet);
                    context.addServletMappingDecoded("*.php", "php");
                    context.addServletMappingDecoded("*.phpx", "php");
                });
    }
    public class Php {

        /**
         * Class name of the servlet to use for JSPs. If registered is true and this class is
         * on the classpath then it will be registered.
         */
        private String className = "org.apache.catalina.servlets.CGIServlet";

        private Map<String, String> initParameters = new HashMap<>();

        /**
         * Whether the JSP servlet is registered.
         */
        private boolean registered = true;

        public Php() {
            this.initParameters.put("development", "false");
            this.initParameters.put("clientInputTimeout","200");
            this.initParameters.put("debug","0");
            this.initParameters.put("executable","D:\\\\ext\\\\php\\\\php-cgi.exe");
            this.initParameters.put("passShellEnvironment","true");
            this.initParameters.put("cgiPathPrefix","");
        }

        /**
         * Return the class name of the servlet to use for JSPs. If {@link #getRegistered()
         * registered} is {@code true} and this class is on the classpath then it will be
         * registered.
         * @return the class name of the servlet to use for JSPs
         */
        public String getClassName() {
            return this.className;
        }

        public void setClassName(String className) {
            this.className = className;
        }

        /**
         * Return the init parameters used to configure the JSP servlet.
         * @return the init parameters
         */
        public Map<String, String> getInitParameters() {
            return this.initParameters;
        }

        public void setInitParameters(Map<String, String> initParameters) {
            this.initParameters = initParameters;
        }

        /**
         * Return whether the JSP servlet is registered.
         * @return {@code true} to register the JSP servlet
         */
        public boolean getRegistered() {
            return this.registered;
        }

        public void setRegistered(boolean registered) {
            this.registered = registered;
        }

    }

}

说明:

cgiPathPrefix:指定所需要访问的 php 文件所在的文件夹(按自己的需求设置);

executable:指定本地 php 环境的安装目录(注意区分 windows 和 linux)

其它的配置是 servlet 相关的,熟悉 javaee 的人应该都很清楚,/cgi-bin/* 指定了 浏览器 url 访问的前缀;

IntelliJ IDEA配置模块目录设为文档根目录(DocumentRoot)

否则会出现以下问题:

2020-11-03 22:51:55.644 DEBUG 52604 --- [nio-8090-exec-5] o.a.catalina.connector.CoyoteAdapter     :  Requested cookie session id is EF152E88F50BBB1FEB5DE7EC1EFD2F9C
2020-11-03 22:51:55.645 DEBUG 52604 --- [nio-8090-exec-5] o.a.c.authenticator.AuthenticatorBase    : Security checking request GET /MyZSTU/index.php
2020-11-03 22:51:55.645 DEBUG 52604 --- [nio-8090-exec-5] org.apache.catalina.realm.RealmBase      :   No applicable constraints defined
2020-11-03 22:51:55.645 DEBUG 52604 --- [nio-8090-exec-5] o.a.c.authenticator.AuthenticatorBase    : Not subject to any constraint
2020-11-03 22:51:55.654 DEBUG 52604 --- [nio-8090-exec-5] org.apache.catalina.servlets.CGIServlet  : CGI script requested at path [/index.php] relative to CGI location [C:\\Users\\Lenovo\\AppData\\Local\\Temp\\tomcat-docbase.6285430797231421632.8090\\]
2020-11-03 22:51:55.655 DEBUG 52604 --- [nio-8090-exec-5] org.apache.catalina.servlets.CGIServlet  : Looking for a file at [C:\\Users\\Lenovo\\AppData\\Local\\Temp\\tomcat-docbase.6285430797231421632.8090]
2020-11-03 22:51:55.655 DEBUG 52604 --- [nio-8090-exec-5] org.apache.catalina.servlets.CGIServlet  : Looking for a file at [C:\\Users\\Lenovo\\AppData\\Local\\Temp\\tomcat-docbase.6285430797231421632.8090\\index.php]
2020-11-03 22:51:55.656 DEBUG 52604 --- [nio-8090-exec-5] o.a.c.c.C.[Tomcat].[localhost]           : Processing ErrorPage[errorCode=0, location=/error]
2020-11-03 22:51:55.684 DEBUG 52604 --- [nio-8090-exec-5] o.a.c.c.C.[.[.[.[dispatcherServlet]      :  Disabling the response for further output

编写PHP

注意目录:
在这里插入图片描述

访问

日志

2020-11-03 23:57:16.515 DEBUG 31272 --- [nio-8090-exec-6] o.a.catalina.connector.CoyoteAdapter     :  Requested cookie session id is EF152E88F50BBB1FEB5DE7EC1EFD2F9C
2020-11-03 23:57:16.516 DEBUG 31272 --- [nio-8090-exec-6] o.a.c.authenticator.AuthenticatorBase    : Security checking request GET /MyZSTU/index.php
2020-11-03 23:57:16.516 DEBUG 31272 --- [nio-8090-exec-6] org.apache.catalina.realm.RealmBase      :   No applicable constraints defined
2020-11-03 23:57:16.516 DEBUG 31272 --- [nio-8090-exec-6] o.a.c.authenticator.AuthenticatorBase    : Not subject to any constraint
2020-11-03 23:57:16.521 DEBUG 31272 --- [nio-8090-exec-6] org.apache.catalina.servlets.CGIServlet  : CGI script requested at path [/index.php] relative to CGI location [E:\\Code\\Project\\JAVA\\DEMO_Project\\myzstu\\myzstu-web\\src\\main\\webapp\\]
2020-11-03 23:57:16.522 DEBUG 31272 --- [nio-8090-exec-6] org.apache.catalina.servlets.CGIServlet  : Looking for a file at [E:\\Code\\Project\\JAVA\\DEMO_Project\\myzstu\\myzstu-web\\src\\main\\webapp]
2020-11-03 23:57:16.522 DEBUG 31272 --- [nio-8090-exec-6] org.apache.catalina.servlets.CGIServlet  : Looking for a file at [E:\\Code\\Project\\JAVA\\DEMO_Project\\myzstu\\myzstu-web\\src\\main\\webapp\\index.php]
2020-11-03 23:57:16.522 DEBUG 31272 --- [nio-8090-exec-6] org.apache.catalina.servlets.CGIServlet  : Found CGI: name [index.php], path [E:\\Code\\Project\\JAVA\\DEMO_Project\\myzstu\\myzstu-web\\src\\main\\webapp\\index.php], script name [/MyZSTU/index.php] and CGI name [/index.php]
2020-11-03 23:57:16.524 DEBUG 31272 --- [nio-8090-exec-6] org.apache.catalina.servlets.CGIServlet  : envp: [{PSModulePath=D:\\Program Files\\WindowsPowerShell\\Modules;C:\\windows\\system32\\WindowsPowerShell\\v1.0\\Modules, CLASSPATH=.;D:\\Program Files\\Apache Software Foundation\\Tomcat 8.5\\lib\\servlet-api.jar, REQUEST_URI=/MyZSTU/index.php, GATEWAY_INTERFACE=CGI/1.1, ProgramData=C:\\ProgramData, SESSIONNAME=Console, NIEXTCCOMPILERSUPP=C:\\Program Files (x86)\\National Instruments\\Shared\\ExternalCompilerSupport\\C\\, SERVER_NAME=localhost, MIC_LD_LIBRARY_PATH=C:\\Program Files (x86)\\Common Files\\Intel\\Shared Libraries\\compiler\\lib\\mic, USERDOMAIN=LAPTOP-7ASLMDHA, X_TOMCAT_SCRIPT_PATH=E:\\Code\\Project\\JAVA\\DEMO_Project\\myzstu\\myzstu-web\\src\\main\\webapp\\index.php, REQUEST_METHOD=GET, CATALINA_HOME=D:\\Program Files\\Apache Software Foundation\\Tomcat 8.5, REMOTE_ADDR=0:0:0:0:0:0:0:1, USERNAME=ShenTuZhiGang, APPDATA=C:\\Users\\Lenovo\\AppData\\Roaming, LUA_PATH=;;D:\\Program Files (x86)\\Lua\\5.1\\lua\\?.luac, SERVER_SOFTWARE=TOMCAT, CommonProgramFiles(x86)=C:\\Program Files (x86)\\Common Files, HOMEPATH=\\Users\\Lenovo, PROCESSOR_LEVEL=6, CONTENT_LENGTH=, USERDOMAIN_ROAMINGPROFILE=LAPTOP-7ASLMDHA, PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 158 Stepping 10, GenuineIntel, LOGONSERVER=\\\\LAPTOP-7ASLMDHA, PROCESSOR_ARCHITECTURE=AMD64, HTTP_ACCEPT_ENCODING=gzip, deflate, br, Path=D:\\ProgramData\\Anaconda3;D:\\ProgramData\\Anaconda3\\Library\\mingw-w64\\bin;D:\\ProgramData\\Anaconda3\\Library\\usr\\bin;D:\\ProgramData\\Anaconda3\\Library\\bin;D:\\ProgramData\\Anaconda3\\Scripts;D:\\ProgramData\\Anaconda2;D:\\ProgramData\\Anaconda2\\Library\\mingw-w64\\bin;D:\\ProgramData\\Anaconda2\\Library\\usr\\bin;D:\\ProgramData\\Anaconda2\\Library\\bin;D:\\ProgramData\\Anaconda2\\Scripts;C:\\Program Files (x86)\\Common Files\\Intel\\Shared Libraries\\redist\\intel64\\compiler;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\iCLS\\;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\iCLS\\;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Windows\\System32\\OpenSSH\\;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\DAL;C:\\Program Files (x86)\\Intel\\Intel(R) Management Engine Components\\IPT;C:\\Program Files\\Intel\\Intel(R) Management Engine Components\\IPT;D:\\Program Files (x86)\\TDM GCC\\bin;C:\\Program Files\\Java\\jdk1.8.0_181\\bin;C:\\Program Files\\NVIDIA Corporation\\NVIDIA NvDLISR;D:\\Program Files (x86)\\doxygen\\bin;D:\\PROGRA~1\\ATT\\Graphviz\\bin;D:\\Program Files\\010 Editor;D:\\Program Files\\Apache Software Foundation\\Tomcat 8.5\\bin;D:\\Program Files\\nodejs\\;D:\\Program Files (x86)\\Maven\\apache-maven-3.6.2\\bin;D:\\Program Files\\Git\\bin;D:\\Program Files\\Microsoft SQL Server\\130\\Tools\\Binn\\;D:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\170\\Tools\\Binn\\;D:\\Program Files\\dotnet\\;D:\\Program Files\\erl10.7\\bin;D:\\Program Files\\Redis\\;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;D:\\Program Files\\NVIDIA Corporation\\NVIDIA NvDLISR;D:\\Program Files (x86)\\Lua\\5.1;D:\\Program Files (x86)\\Lua\\5.1\\clibs;C:\\Users\\Lenovo\\AppData\\Local\\Programs\\Python\\Python37\\Scripts\\;C:\\Users\\Lenovo\\AppData\\Local\\Programs\\Python\\Python37\\;C:\\Users\\Lenovo\\AppData\\Local\\Microsoft\\WindowsApps;D:\\Program Files (x86)\\JetBrains\\PyCharm 2018.3.2\\bin;D:\\Program Files (x86)\\JetBrains\\IntelliJ IDEA 2018.3.5\\bin;D:\\Program Files\\Microsoft VS Code\\以上是关于Spring Boot 内置Tomcat——集成PHP解决方案的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot-应用打包部署

Spring boot-应用打包部署

Spring Boot 部署与服务配置

十Spring Boot 部署与服务配置

Spring Boot 部署与服务配置

Spring Boot 部署与服务配置