You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.dsideal.gw.Handler;
import com.dsideal.gw.Bean.RetBean;
import com.dsideal.gw.GwApplication;
import com.dsideal.gw.Util.JwtUtil;
import com.dsideal.gw.Util.SessionKit;
import com.jfinal.handler.Handler;
import com.jfinal.kit.StrKit;
import com.jfinal.upload.MultipartRequest;
import com.jfinal.upload.UploadFile;
import io.jsonwebtoken.Claims;
import okhttp3.*;
import org.apache.commons.io.IOUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
/**
* 测试用例:
* GET
* http://10.10.21.20:8000/dsBase/dm/getDmSchoolProperty
* http://10.10.21.20:8000/dsBase/global/getGlobalList?page=1&limit=10
* POST
* http://10.10.21.20:8000/dsBase/global/testPost?a=100
* 上传文件
* http://10.10.21.20:8000/dsBase/global/testUpload
* form-data
* upfile --->参数值:选择一个文件 类型file
*/
public class RouterHandler extends Handler {
//OkHttp的实例单例模式
private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient();
/**
* 功能输出JSON文本串
*
* @param res
*/
public void renderJson(HttpServletResponse res, String body) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Cache-Control", "no-cache");
res.setCharacterEncoding("UTF-8");
res.setContentType("application/json");
try {
res.getWriter().println(body);
res.getWriter().flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//OkHttp的回调函数同步执行
private void executeRequest(Request request, HttpServletResponse res) throws IOException {
Response response = OK_HTTP_CLIENT.newCall(request).execute();
if (response.isSuccessful()) {
ResponseBody body = response.body();
if (body != null) {
// 获取Content-Type
String contentType = response.header("Content-Type");
if (contentType != null && contentType.startsWith("image/")) {
// 处理图片响应
handleImageResponse(res, body, contentType);
} else {
// 处理文本响应
handleTextResponse(res, body);
}
} else {
renderJson(res, new RetBean(RetBean.ERROR, "响应体为空").toString());
}
} else {
renderJson(res, new RetBean(RetBean.ERROR, "请求失败!").toString());
}
}
// 处理图片响应
private void handleImageResponse(HttpServletResponse res, ResponseBody body, String contentType) throws IOException {
// 设置响应头
res.setContentType(contentType);
res.setHeader("Cache-Control", "no-store");
res.setHeader("Pragma", "no-cache");
res.setDateHeader("Expires", 0);
// 将图片数据写入响应
try (InputStream inputStream = body.byteStream()) {
IOUtils.copy(inputStream, res.getOutputStream());
}
}
// 处理文本响应
private void handleTextResponse(HttpServletResponse res, ResponseBody body) throws IOException {
String responseBody = body.string();
renderJson(res, responseBody);
}
public static RequestBody createRequestBody(HttpServletRequest req) {
FormBody.Builder formBodyBuilder = new FormBody.Builder();
// 遍历请求中的参数
Enumeration<String> parameterNames = req.getParameterNames();
while (parameterNames.hasMoreElements()) {
String paramName = parameterNames.nextElement();
String paramValue = req.getParameter(paramName);
formBodyBuilder.add(paramName, paramValue);
}
// 构建RequestBody
return formBodyBuilder.build();
}
@Override
public void handle(String target, HttpServletRequest req, HttpServletResponse res, boolean[] isHandled) {
//可以正确获取到URL的完整路径
String servletPath = req.getServletPath();
String queryString = req.getQueryString();
//对于根目录的访问,放行
if (servletPath.equals("/")) {
next.handle(target, req, res, isHandled);
return;
}
//如果是白名单不检查jwt,否则需要检查jwt
if (!GwApplication.whiteSet.contains(servletPath)) {
//微服务间的调用视为内部调用
if (req.getServletPath().endsWith("_Internal")) {
renderJson(res, new RetBean(RetBean.ERROR, "微服务间内部接口调用,是不需要走网关的!").toString());
isHandled[0] = true; //停止filter
return;
}
//是不是通过了登录检查?
boolean canPass = true;
//1、存在Session,检查是不是正确的Session
String identity_id = SessionKit.get(req, res, "identity_id");
String person_id = SessionKit.get(req, res, "person_id");
String bureau_id = SessionKit.get(req, res, "bureau_id");
String token = SessionKit.get(req, res, "token");
//如果没有找到Session那么直接不通过
if (StrKit.isBlank(token) || StrKit.isBlank(bureau_id) || StrKit.isBlank(identity_id) || StrKit.isBlank(person_id)) {
canPass = false;
}
if (!canPass) {
//如果不存在Session,那么检查是不是存在JWT,并且JWT是不是正确的
if (req.getHeader("Authorization") != null) {
String jwtToken = req.getHeader("Authorization");
Claims claims = JwtUtil.getClaims(jwtToken);
if (claims != null) {
canPass = true;
}
}
}
if (!canPass) {
renderJson(res, new RetBean(RetBean.ERROR, "登录已过期,请重新登录!").toString());
isHandled[0] = true; //停止filter
return;
}
}
//路由到哪个微服务
int xie1 = servletPath.indexOf('/'); // 找到第一个 '/' 的索引
int xie2 = servletPath.indexOf('/', xie1 + 1); // 从第一个 '/' 之后开始找第二个 '/' 的索引
//action名称
String action = servletPath.substring(xie2 + 1);
if (xie1 == -1 || xie2 == -1) {
renderJson(res, new RetBean(RetBean.ERROR, "输入的字符串格式不正确,没有找到两个 '/'。").toString());
isHandled[0] = true; //停止filter
return;
}
String prefix = servletPath.substring(xie1 + 1, xie2); // 截取两个 '/' 之间的内容
if (!GwApplication.routeList.containsKey(prefix)) {
renderJson(res, new RetBean(RetBean.ERROR, prefix + "前缀没有找到合适的路由表,请检查是否请求正确!").toString());
isHandled[0] = true; //停止filter
return;
}
//路由到哪个微服务
String FORWARD_URL = GwApplication.routeList.get(prefix) + "/" + prefix + "/" + action;
//1、如果是上传文件
if (req.getMethod().equals("POST") && req.getContentType() != null && req.getContentType().startsWith("multipart/form-data")) {
// 指定文件类型
MediaType mediaType = MediaType.parse("multipart/form-data");
MultipartRequest mp = new MultipartRequest(req);
List<UploadFile> files = mp.getFiles();
if (files.isEmpty()) {
renderJson(res, new RetBean(RetBean.ERROR, "没有上传文件!").toString());
isHandled[0] = true;//停止filter
return;
}
UploadFile uploadFile = files.getFirst();
// 获取文件流
RequestBody requestBody = RequestBody.create(uploadFile.getFile(), mediaType);
// 构建MultipartBody
MultipartBody body = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", uploadFile.getFileName(), requestBody)
.build();
// 构建Request
Request request = new Request.Builder()
.url(FORWARD_URL)
.post(body)
.build();
try {
executeRequest(request, res);
isHandled[0] = true;//停止filter
return;
} catch (Exception e) {
renderJson(res, new RetBean(RetBean.ERROR, "请求失败!" + e).toString());
isHandled[0] = true;//停止filter
return;
}
}
//2、处理GET请求
if (req.getMethod().equals("GET")) {
//参数:queryString
Request.Builder builder;
if (queryString != null) {
builder = new Request.Builder().url(FORWARD_URL + "?" + queryString);
} else {
builder = new Request.Builder().url(FORWARD_URL);
}
if (!StrKit.isBlank(req.getHeader("Authorization"))) {
builder.addHeader("Authorization", req.getHeader("Authorization"));
builder.addHeader("Accept", "application/json;odata=verbose");
}
Request request = builder.build();
try {
executeRequest(request, res);
isHandled[0] = true;//停止filter
return;
} catch (IOException e) {
renderJson(res, new RetBean(RetBean.ERROR, "请求失败!" + e).toString());
isHandled[0] = true;//停止filter
return;
}
}
//3、处理POST请求
if (req.getMethod().equals("POST")) {
RequestBody body = createRequestBody(req);
Request.Builder builder;
if (queryString != null) {
builder = new Request.Builder().url(FORWARD_URL + "?" + queryString);
} else {
builder = new Request.Builder().url(FORWARD_URL);
}
if (!StrKit.isBlank(req.getHeader("Authorization"))) {
builder.addHeader("Authorization", req.getHeader("Authorization"));
builder.addHeader("Accept", "application/json;odata=verbose");
}
builder.post(body);
Request request = builder.build();
try {
executeRequest(request, res);
isHandled[0] = true;//停止filter
return;
} catch (IOException e) {
renderJson(res, new RetBean(RetBean.ERROR, "请求失败!" + e).toString());
isHandled[0] = true;//停止filter
return;
}
}
//4、其它的OPTIONS
renderJson(res, new RetBean(RetBean.ERROR, "系统只支持GET,POST其它的OPTIONS不支持文件上传请使用S3协议进行直传不通过JAVA处理JAVA只处理授权").toString());
//停止filter
isHandled[0] = true;
}
}