java後端路由中轉

1 背景    

        在目前的項目開發過程中,通常採用前後端分離的架構並行開發。而前後端開發通常項目也是分開部署實現的。也就是前端和後端是由兩個服務器分開部署,而後端通常也是多模塊並行開發的,這就會造成前端項目無法訪問後端項目的接口。這時,如果後端能夠實現路由轉發的話,就可以實現後端多個模塊之間相互調用,從而解決上面出現的問題。

2 基本思路

      由於後端各個模塊相互獨立,所以無法修改後端模塊實現。通常我們會採用在前端項目中新增一個路由中轉器,實現通常url的不同進行跳轉到不同的項目中,從而訪問到後端的各個接口。

實現方式:URL(跳轉信息)+後端路由轉發

 

3 代碼實現

3.1 攔截controller

@Controller
@RequestMapping(value = "/user/redirect")
public class RedirectController {

    //在user項目中關於其它子項目比如trade項目的jsp頁面
    //ajax請求需要加上前綴/user/redirect
    private static int offset = "/user/redirect/".length();
    private static Logger logger = Logger.getLogger(RedirectController.class);

    @ApiOperation(value = "重定向", hidden = true)
    @RequestMapping(value = "/**", method = {RequestMethod.POST, RequestMethod.GET})
    public void redirect(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String url = request.getRequestURI();
        int base = request.getContextPath().length();
        String host = url.substring(base + offset, url.indexOf("/",base + offset));//例如: trade
        logger.info("request.getRequestURI():"+request.getRequestURI()+"\tbase:"+base+"\thost:"+host);
        //host url request response additionalMap
        HttpUtil.httpRequest(host, url.substring(url.indexOf("/",base + offset)),//例如: /allProduction/getAllProductionPage
                request, response, new ArrayList<NameValuePair>());
        response.getOutputStream().flush();
        response.getOutputStream().close();
    }

}

3.2 HttpUtil

package edu.whut.imgProcess.redirect;

import org.apache.http.*;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * com.whut.athena.util
 * Created by YTY on 2016/4/5.
 */
public class HttpUtil {
    private static Logger logger = Logger.getLogger(HttpUtil.class);

    public static void httpRequest(String hostPrefix, String url, HttpServletRequest request, HttpServletResponse response,
                                   List<NameValuePair> additionalMap) {
        CloseableHttpClient httpClient = SSLUtils.createSSLClientDefault();
        HttpPost httpPost = new HttpPost(RedirectUtil.getHost(hostPrefix, url));
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            if (headerName.startsWith("accept") || headerName.startsWith("cookie")) {
                httpPost.addHeader(headerName, request.getHeader(headerName));
            }
        }
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String parameterName = parameterNames.nextElement();
            for (String value : request.getParameterValues(parameterName)) {
                if (value!=null&&!value.equals("null")) params.add(new BasicNameValuePair(parameterName, value));
                //logger.info(parameterName + ":" + value);
            }
        }
        params.addAll(additionalMap);
        for (NameValuePair map : additionalMap) {
            //logger.info(map.getName() + ":" + map.getValue());
        }
        HttpResponse httpResponse = null;
        try {
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, RedirectUtil.SERVER_CHARSET);
            httpPost.setEntity(entity);
            httpResponse = httpClient.execute(httpPost);
            if (httpResponse != null) {
                HttpEntity responseEntity = httpResponse.getEntity();
                if (responseEntity != null) {
                    //logger.info(responseEntity.toString());
                    responseEntity.writeTo(response.getOutputStream());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (httpResponse != null) {
            response.setStatus(httpResponse.getStatusLine().getStatusCode());
            //logger.info(httpResponse.toString());
            HeaderIterator headerIterator = httpResponse.headerIterator();
            while (headerIterator.hasNext()) {
                Header header = headerIterator.nextHeader();
                if (header.getName().equals("Content-Type")) {
                    //response.addHeader(header.getName(), header.getValue());
                    response.setHeader(header.getName(), header.getValue());//或許可以解決重定向亂碼(好像沒影響)
                }
            }
            response.setHeader("Server", "nginx");
        }
    }

    public static String httpRequest(String hostPrefix, String url, List<NameValuePair> params) {
        CloseableHttpClient httpClient = SSLUtils.createSSLClientDefault();
        logger.info(url);
        HttpPost httpPost = new HttpPost(RedirectUtil.getHost(hostPrefix, url));
        try {
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, RedirectUtil.SERVER_CHARSET);
            httpPost.setEntity(entity);
            HttpResponse httpResponse = httpClient.execute(httpPost);
            if (httpResponse != null) {
                HttpEntity responseEntity = httpResponse.getEntity();
                if (responseEntity != null) {
                    String result = EntityUtils.toString(responseEntity, RedirectUtil.SERVER_CHARSET);
                    logger.info(result);
                    return result;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}

3.3 重定向工具類(本地和服務器能不同場景自動切換)

public class RedirectUtil {

    public static boolean DEBUG;

    public static String getServerHost() {
        return SERVER_HOST;
    }

    static String SERVER_HOST;
    static int SERVER_PORT;
    static String SERVER_PROTOCOL;
    static String SERVER_CHARSET;
    static Map<String, String> hostPrefixMap;

    static {
        ResourceBundle bundle = ResourceBundle.getBundle("server");
        SERVER_HOST = bundle.getString("host");
        SERVER_PORT = Integer.parseInt(bundle.getString("port"));
        SERVER_PROTOCOL = bundle.getString("protocol");
        SERVER_CHARSET = bundle.getString("charset");
        DEBUG = SERVER_HOST.equals("localhost");
        hostPrefixMap = new HashMap<String, String>();
        hostPrefixMap.put("user", bundle.getString("user"));
        hostPrefixMap.put("algorithm", bundle.getString("algorithm"));
        hostPrefixMap.put("image", bundle.getString("image"));
    }

    //獲取是否爲本地調試
    public static Boolean getDebug(){
        return DEBUG;
    }

    public static String getHost(String hostPrefix) {
        return getHost(hostPrefix, "");
    }

    public static String getHost(String hostPrefix, String url) {
        hostPrefix = hostPrefixMap.get(hostPrefix);//例如: trade
        String host = SERVER_HOST;
        if (hostPrefix != null && !hostPrefix.isEmpty()) {
            if (DEBUG) {
                //如果是user的話就不需要轉發
                //DEBUG代表本地只需要改變url前綴即可
                url = "/" + hostPrefix + url;//例如: / + image + /image/report/getReportList
            } else {
                //host = hostPrefix + "." + host;//例如: app + . + ceks100.com
                if(hostPrefix.equals("user")){
                    //服務器上的話改變host即可,不需要改變url前綴
                    host = "td9faceusers.d9lab.net";//例如: user服務器
                }
                else if(hostPrefix.equals("algorithm")){
                    host = "td9facealgorithm.d9lab.net";
                }
                else if(hostPrefix.equals("image")){
                    host = "td9faceimages.d9lab.net";
                }
            }
        }
        try {
            if(DEBUG){
                return new URL(SERVER_PROTOCOL, host, SERVER_PORT, url).toString();
            }
            else {
                return new URL(SERVER_PROTOCOL, host, url).toString();  //服務器上不要Port
            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
            return SERVER_PROTOCOL + "://" + host + ":" + SERVER_PORT + "url";
        }
    }
}

 

4 總結

    通過後端路由轉發,可以實現後端多個模塊並行開發,同時也能獨立部署,大大提高了開發的效率。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章