日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達者為師

網(wǎng)站首頁 編程語言 正文

合理使用gateWay過濾器,實現(xiàn)Concroller自動注入用戶信息

作者:earthly exile丶 更新時間: 2022-07-12 編程語言

????????在日常開發(fā)中,經(jīng)常我們需要在請求controller時傳遞用戶信息。那么有沒有一種方式可以讓我們的程序在用戶登錄后自動向controller接口中注入用戶用戶信息呢?

? ? ? ?答案是yes!!!現(xiàn)在我們來看看博主當(dāng)前的項目是如何實現(xiàn)的吧!

? ? ? ? 1.首先登錄時,賬號密碼校驗通過后生成一個token,并將用戶基本信息存入redis。將key返回給前端。

? ? ? ? 2.前端收到后將當(dāng)前用戶的token緩存起來,每次像后臺發(fā)請求時在header中攜帶token。

? ? ? ? 3.重點來了,在gateway中添加一個過濾器,在過濾器中獲取到tocken,用token作為鍵,去redis中獲取用戶的賬號,以及診所等基本信息。并將這些信息拼接到url后面。代碼示例如下:

package com.lvyuanji.gateway.filter;

import cn.hutool.core.util.StrUtil;
import com.lvyuanji.account.api.service.IAccountAdminApiService;
import com.lvyuanji.common.consts.SystemConsts;
import com.lvyuanji.common.vo.redis.AccountEntity;
import com.lvyuanji.common.vo.redis.SalesmanLoginVo;
import com.lvyuanji.stock.api.service.ISalesmanApiService;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;


@Component
public class AccountRequestParameterGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    private static final Logger logger = LoggerFactory.getLogger(AccountRequestParameterGatewayFilterFactory.class);

    @Reference
    private IAccountAdminApiService accountAdminApiService;
    @Reference
    private ISalesmanApiService salesmanApiService;

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerHttpRequest request = exchange.getRequest();
                URI uri = request.getURI();
                StringBuilder query = new StringBuilder();
                String originalQuery = uri.getRawQuery();

                if (StringUtils.hasText(originalQuery)) {
                    query.append(originalQuery);
                    if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
                        query.append('&');
                    }
                }

                String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
                // TODO urlencode?
                query.append(config.getName());
                query.append('=');
                query.append(value);

                String method = request.getMethodValue();
                if ("GET".equals(method.toUpperCase())) {
                    logger.info("【GET】請求 URI:{} 參數(shù):{}", uri.getPath(), query);
                }

                //獲取redis中用戶的緩存信息,拼接到請求參數(shù)后面
                HttpHeaders headers = exchange.getRequest().getHeaders();
                String token = headers.getFirst("token");
                if (StringUtils.hasText(token)) {
                    AccountEntity accountEntity = accountAdminApiService.loginAccountAdmin(token);
                    if (accountEntity != null) {
                        //先去header中獲取診所ID,如果沒有去請求參數(shù)中獲取
                        String tenantId = headers.getFirst("tenantId");
                        if (StringUtils.hasText(tenantId)) {
                            accountEntity.setTenantId(Long.valueOf(tenantId));
                        } else {
                            List<String> tenantIds = request.getQueryParams().get("tenantId");
                            if (!CollectionUtils.isEmpty(tenantIds)) {
                                accountEntity.setTenantId(Long.valueOf(tenantIds.get(0)));
                            }
                        }
                        //封裝其他參數(shù)
                        Map<String, Object> beanMap = beanValue(accountEntity);
                        if (!CollectionUtils.isEmpty(beanMap)) {
                            for (String key : beanMap.keySet()) {
                                try {
                                    Object obj = beanMap.get(key);
                                    String param = obj != null ? URLEncoder.encode(obj.toString(), "UTF-8") : null;
                                    query.append('&').append(key).append('=').append(param);
                                } catch (UnsupportedEncodingException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    } else {
                        //獲取應(yīng)用類型
                        String appType = StrUtil.isNotEmpty(request.getHeaders().getFirst(SystemConsts.APP_TYPE)) ? request.getHeaders().getFirst(SystemConsts.APP_TYPE) : "";
                        if ("applets".equals(appType)) {
                            query.append("&").append("userType").append("=").append("SALESMAN");
                        }
                    }
                } else {
                    String tenantId = headers.getFirst("tenantId");
                    if (StringUtils.hasText(tenantId)) {

                        query.append('&').append("tenantId").append('=').append(tenantId);
                    }
                }

                try {
                    String queryStr = filterOperator(query.toString());
                    URI newUri = UriComponentsBuilder.fromUri(uri)
                            .replaceQuery(queryStr).build(true).toUri();
                    ServerHttpRequest req = exchange.getRequest().mutate().uri(newUri)
                            .build();

                    return chain.filter(exchange.mutate().request(req).build());
                } catch (RuntimeException ex) {
                    throw new IllegalStateException(
                            "Invalid URI query: \"" + query.toString() + "\"");
                }
            }

            @Override
            public String toString() {
                return filterToStringCreator(AccountRequestParameterGatewayFilterFactory.this)
                        .append(config.getName(), config.getValue()).toString();
            }
        };
    }

    /**
     * 過濾特殊字符
     *
     * @param target
     * @return
     */
    private String filterOperator(String target) {
        target = target.replace("[", "");
        return target.replace("]", "");
    }

    /**
     * 獲取bean的屬性和值
     *
     * @param bean
     * @return
     */
    private Map<String, Object> beanValue(AccountEntity bean) {
        Map<String, Object> result = new HashMap<>();
        Class clazz = bean.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();
            field.setAccessible(true);
            Object value = null;
            try {
                value = field.get(bean);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            if (value != null) {
                result.put(name, value);
            }
        }
        return result;
    }

}

????????4.spring參數(shù)解析器會自動將url后面的參數(shù)解析為對應(yīng)的AccountBean,這樣我們在需要用到Account信息的Controller方法中只需要在參數(shù)中加入AccountBean參數(shù)即可,。前端也不必刻意傳Account信息,因為Header中攜帶了Token。

? ? ? ?

原文鏈接:https://blog.csdn.net/weixin_47987440/article/details/125694110

欄目分類
最近更新