Spring第三方接口Api工具类

背景

由于项目上经常要对接第三方的api,各类http工具类编码繁琐,定义接口不明确,所以就基于spring的RestTemplate封装了一个可读性高的工具类,方便接口管理

特性

  • 采用函数+链式方式直观展现接口定义
  • 支持一键开启日志,formdata请求转换
  • 内置 javabean 到 queryparam 和 path占位符 的自动映射
  • 支持定制请求客户端

代码:

import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.lang.NonNull;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StopWatch;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author Alone
 */
public interface Api<IN, OUT> extends Function<IN, OUT> {

    /**
     * Api构建器
     *
     * @param reqClass  请求
     * @param respClass 响应
     * @param <IN>      reqClass
     * @param <OUT>     respClass
     * @return Api构建器
     */
    static <IN, OUT> Builder<IN, OUT> builder(Class<? extends IN> reqClass, Class<? extends OUT> respClass) {
        return new Builder<>(reqClass, respClass);
    }

    /**
     * Api构建器, 没有动态入参,写死的请求
     *
     * @param respClass 响应
     * @param <OUT>     respClass
     * @return Api构建器
     */
    static <OUT> Builder<Void, OUT> builder(Class<? extends OUT> respClass) {
        return new Builder<>(Void.class, respClass);
    }

    /**
     * Api构建器, 没有动态入参,写死的请求
     *
     * @return Api构建器
     */
    static Builder<Void, String> builder() {
        return new Builder<>(Void.class, String.class);
    }


    /**
     * 执行请求
     *
     * @param in 入参
     * @return OUT
     */
    default OUT exec(IN in) {
        return apply(in);
    }

    /**
     * 空入参
     *
     * @return OUT
     */
    default OUT exec() {
        return apply(null);
    }


    /**
     * 返回当前备份的构建器以创建其他副本
     *
     * @return Api.BuilderEditor<IN, OUT>
     */
    Api.BuilderEditor<IN, OUT> customize();

    class Builder<IN, OUT> {

        public static final RestTemplate DEFAULT_CLIENT;
        private static final Logger LOG = LoggerFactory.getLogger(Builder.class);

        // init client
        static {
            try {
                // 可以自己定制下
                SSLContext context = SSLContext.getInstance("TLSv1.2");
                context.init(null, null, null);
                HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
                        HttpClientBuilder
                                .create()
                                .setSSLContext(context)
                                .build()
                );
                factory.setConnectTimeout(50000);

                DEFAULT_CLIENT = new RestTemplate(factory);
                // 处理500的请求直接抛错的问题
                DEFAULT_CLIENT.setErrorHandler(new ResponseErrorHandler() {
                    @Override
                    public boolean hasError(@NonNull ClientHttpResponse resp) throws IOException {
                        System.out.println(resp.getStatusCode());
                        System.out.println(resp.getHeaders());
                        System.out.println(resp.getBody());
                        return false;
                    }

                    @Override
                    public void handleError(@NonNull ClientHttpResponse resp) {
                    }
                });
            } catch (Exception e) {
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                } else {
                    throw new RuntimeException(e);
                }
            }
        }

        // base data
        private final Class<? extends IN> reqClass;
        private final Class<? extends OUT> respClass;
        private String url;
        private HttpMethod method = HttpMethod.GET;
        private MultiValueMap<String, Function<IN, String>> header;
        private List<Function<IN, Map<String, String>>> headers;
        private Map<String, Function<IN, Object>> param;
        private Map<String, Function<IN, Object>> path;
        private Set<String> pathValPlaceholder;
        private Function<IN, ?> body;
        private RestOperations client = DEFAULT_CLIENT;
        private Function<Object, OUT> resultMapper;
        // feature

        /**
         * 以application/x-www-form-urlencoded方式提交body
         * 默认为application/json格式
         */
        private boolean formData = false;

        /**
         * 请求信息打印
         */
        private boolean log = false;

        /**
         * 自动从param中取path需要到参数
         * 不需要通过方法 {@link #path(String, Function)} {@link #path(String, Object)} 设置值,不过优先级是这两个方法高
         */
        private boolean autoMapParamToPath = true;

        public Builder(Class<? extends IN> reqClass, Class<? extends OUT> respClass) {
            this.reqClass = reqClass;
            this.respClass = respClass;
        }

        /**
         * 设置请求客户端
         */
        public Builder<IN, OUT> client(RestOperations client) {
            this.client = client;
            return this;
        }

        /**
         * 将 body 以 form data 表单提交
         */
        public Builder<IN, OUT> enableFormData() {
            this.formData = true;
            return this;
        }

        /**
         * 开启日志
         */
        public Builder<IN, OUT> enableLog() {
            this.log = true;
            return this;
        }


        public Builder<IN, OUT> disableAutoMapParamToPath() {
            this.autoMapParamToPath = false;
            return this;
        }

        /**
         * 将入参完全映射到param
         */
        public Builder<IN, OUT> mapToParam() {
            PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(reqClass);
            if (this.param == null) {
                this.param = new HashMap<>(propertyDescriptors.length);
            }
            mapTo(param, propertyDescriptors);
            return this;
        }

        /**
         * 将入参完全映射到path
         */
        public Builder<IN, OUT> mapToPath() {
            PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(reqClass);
            if (this.path == null) {
                this.path = new HashMap<>(propertyDescriptors.length);
            }
            mapTo(path, propertyDescriptors);
            return this;
        }

        /**
         * 将入参完全映射到body
         */
        public Builder<IN, OUT> mapToBody() {
            this.body = in -> in;
            return this;
        }

        private void mapTo(Map<String, Function<IN, Object>> container, PropertyDescriptor[] data) {
            for (PropertyDescriptor propertyDescriptor : data) {
                // 忽略getClass()方法
                if ("class".equals(propertyDescriptor.getName())) {
                    continue;
                }
                container.put(propertyDescriptor.getName(), in -> {
                    if (Objects.isNull(in)) {
                        return null;
                    }
                    try {
                        Method readMethod = propertyDescriptor.getReadMethod();
                        readMethod.setAccessible(true);
                        return readMethod.invoke(in);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        throw new RuntimeException(e);
                    }
                });
            }
        }

        /**
         * 设置请求地址
         */
        public Builder<IN, OUT> url(String url) {
            this.url = url;
            return this;
        }

        /**
         * 设置请求方式
         */
        public Builder<IN, OUT> method(HttpMethod method) {
            this.method = method;
            return this;
        }

        /**
         * 设置请求头
         */
        public Builder<IN, OUT> header(String key, String value) {
            if (this.header == null) {
                this.header = new LinkedMultiValueMap<>();
            }
            this.header.add(key, in -> value);
            return this;
        }

        /**
         * 设置请求头
         */
        public Builder<IN, OUT> header(String key, Function<IN, String> valueFunc) {
            if (this.header == null) {
                this.header = new LinkedMultiValueMap<>();
            }
            this.header.add(key, valueFunc);
            return this;
        }

        public Builder<IN, OUT> headers(Function<IN, Map<String, String>> mapFunc) {
            if (this.headers == null) {
                this.headers = new ArrayList<>();
            }
            headers.add(mapFunc);
            return this;
        }

        /**
         * 设置请求参数
         */
        public Builder<IN, OUT> param(String key, Object value) {
            if (this.param == null) {
                this.param = new HashMap<>(2);
            }
            this.param.put(key, in -> value);
            return this;
        }

        /**
         * 设置请求参数
         */
        public Builder<IN, OUT> param(String key, Function<IN, Object> valueFunc) {
            if (this.param == null) {
                this.param = new HashMap<>(2);
            }
            this.param.put(key, valueFunc);
            return this;
        }

        /**
         * 设置请求路径值
         */
        public Builder<IN, OUT> path(String key, Object value) {
            if (this.path == null) {
                this.path = new HashMap<>(2);
            }
            this.path.put(key, in -> value);
            return this;
        }

        /**
         * 设置请求路径值
         */
        public Builder<IN, OUT> path(String key, Function<IN, Object> valueFunc) {
            if (this.path == null) {
                this.path = new HashMap<>(2);
            }
            this.path.put(key, valueFunc);
            return this;
        }

        /**
         * 设置请求体
         */
        public Builder<IN, OUT> body(Object body) {
            this.body = in -> body;
            return this;
        }

        /**
         * 设置请求体
         */
        public Builder<IN, OUT> body(Function<IN, Object> body) {
            this.body = body;
            return this;
        }

        /**
         * 设置请求体
         */
        public Builder<IN, OUT> body(Consumer<Map<String, Object>> body) {
            Map<String, Object> bodyMap = new HashMap<>(1);
            body.accept(bodyMap);
            this.body = in -> bodyMap;
            return this;
        }

        /**
         * 设置请求体
         */
        public Builder<IN, OUT> multiValBody(Consumer<MultiValueMap<String, Object>> body) {
            MultiValueMap<String, Object> bodyMap = new LinkedMultiValueMap<>();
            body.accept(bodyMap);
            this.body = in -> bodyMap;
            return this;
        }

        public Builder<IN, OUT> resultMapper(Function<Object, OUT> func) {
            this.resultMapper = func;
            return this;
        }

        public Api<IN, OUT> build() {
            check();
            handlePathValue();
            Builder<IN, OUT> ref = this;
            return new Api<IN, OUT>() {
                private BuilderEditor<IN, OUT> editor = null;

                @Override
                public BuilderEditor<IN, OUT> customize() {
                    // lazy load
                    if (editor == null) {
                        editor = BuilderEditor.clone(ref);
                    }
                    return editor;
                }

                @Override
                public OUT apply(IN in) {
                    return execution(in);
                }
            };
        }

        private OUT execution(IN in) {
            MultiValueMap<String, String> mapHeader = apply(in, header);
            if (Objects.nonNull(headers)) {
                if (mapHeader == null) {
                    mapHeader = new LinkedMultiValueMap<>();
                }
                for (Function<IN, Map<String, String>> func : headers) {
                    Map<String, String> apply = func.apply(in);
                    for (String key : apply.keySet()) {
                        mapHeader.add(key, apply.get(key));
                    }
                }
            }
            Object mapBody = Objects.nonNull(body) ? body.apply(in) : null;

            // adapt, format body data to the MultiValueMap
            if (formData) {
                mapHeader = null == mapHeader ? new LinkedMultiValueMap<>(1) : mapHeader;
                mapHeader.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
                mapBody = bodyToMultiValueMap(mapBody);
            }

            HttpEntity<Object> entity;
            if (empty(mapHeader) && null == mapBody) {
                entity = null;
            } else {
                entity = new HttpEntity<>(mapBody, mapHeader);
            }

            // extract param and path data
            Map<String, Object> mapParam = apply(in, param);
            Map<String, Object> mapPath = apply(in, path);

            // log around weave start
            StopWatch stopWatch = null;
            if (log) {
                stopWatch = new StopWatch();
                stopWatch.start();
            }

            OUT res;
            if (Objects.isNull(resultMapper)) {
                res = client.exchange(
                        splicingUriValues(url, mapParam, mapPath),
                        method, entity,
                        respClass).getBody();
            } else {
                Object data = client.exchange(
                        splicingUriValues(url, mapParam, mapPath),
                        method, entity,
                        Object.class).getBody();
                res = resultMapper.apply(data);
            }

            // log around weave end
            if (log) {
                assert stopWatch != null;
                stopWatch.stop();
                String result = null != res ? res.toString() : "";
                LOG.info("\n╔═════════════════请求接口═════════════════╗\n" +
                                "║请求地址:{}\n" +
                                "║请求方式:{}\n" +
                                "║请求头:{}\n" +
                                "║请求参数:{}\n" +
                                "║        {}\n" +
                                "║请求体:{}\n" +
                                "║返回数据:{}\n" +
                                "║请求耗时:{}\n" +
                                "╚═════════════════════════════════════════╝\n",
                        url,
                        method,
                        mapHeader,
                        mapParam,
                        mapPath,
                        mapBody,
                        (result.length() >= 100 ? result.substring(0, 100) + " ..." : result).replace("\n", ""),
                        stopWatch.getTotalTimeMillis() + "ms"
                );
            }

            return res;
        }

        private static final Pattern PATH_VAL_PATTERN = Pattern.compile("\\{(.*?)}");

        private void handlePathValue() {
            Matcher matcher = PATH_VAL_PATTERN.matcher(url);
            Set<String> set = new HashSet<>();
            while (matcher.find()) {
                set.add(matcher.group(1));
            }
            this.pathValPlaceholder = set;
        }

        private void check() {
            if (null == url || url.isEmpty()) {
                throw new IllegalArgumentException("url不能为空");
            }
            if (null == method) {
                throw new IllegalArgumentException("method不能为空");
            }
        }

        /**
         * adapt form data request
         * 将body转换成 MultiValueMap
         */
        @SuppressWarnings({"unchecked", "rawtypes"})
        private MultiValueMap<String, Object> bodyToMultiValueMap(Object body) {
            if (Objects.isNull(body)) {
                return null;
            }
            if (body instanceof MultiValueMap) {
                return (MultiValueMap<String, Object>) body;
            } else if (body instanceof Map) {
                Map<String, Object> bodyMap = (Map) body;
                MultiValueMap<String, Object> res = new LinkedMultiValueMap<>(bodyMap.size());
                bodyMap.forEach((k, v) -> {
                    if (v instanceof List) {
                        res.put(k, (List) v);
                    } else if (v.getClass().isArray()) {
                        res.put(k, Arrays.asList((Object[]) v));
                    } else if (v instanceof Collection) {
                        res.put(k, new ArrayList<>((Collection) v));
                    } else if (v instanceof Iterable) {
                        Iterable it = (Iterable) v;
                        for (Object o : it) {
                            res.add(k, o);
                        }
                    } else {
                        res.add(k, v);
                    }
                });
                return res;
            } else {
                PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(body.getClass());
                MultiValueMap<String, Object> res = new LinkedMultiValueMap<>(propertyDescriptors.length);
                for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                    // 忽略getClass()方法
                    if ("class".equals(propertyDescriptor.getName())) {
                        continue;
                    }
                    Method readMethod = propertyDescriptor.getReadMethod();
                    readMethod.setAccessible(true);
                    try {
                        res.add(propertyDescriptor.getName(), readMethod.invoke(body));
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        throw new RuntimeException(e);
                    }
                }
                return res;
            }
        }

        private String splicingUriValues(String url,
                                         Map<String, Object> requestParams,
                                         Map<String, Object> requestPaths) {
            return splicingUriValues(url, requestParams, requestPaths, pathValPlaceholder, autoMapParamToPath);
        }

        public static String splicingUriValues(String url,
                                               Map<String, Object> requestParams) {
            return splicingUriValues(url, requestParams, null, Collections.emptySet(), false);
        }

        /**
         * 填充 path 和 param
         */
        public static String splicingUriValues(String url,
                                               Map<String, Object> requestParams,
                                               Map<String, Object> requestPaths,
                                               Set<String> pathValPlaceholder,
                                               boolean autoMapParamToPath) {
            boolean emptyParams = empty(requestParams);
            boolean emptyPaths = empty(requestPaths);
            if (emptyParams && emptyPaths) {
                if (empty(pathValPlaceholder)) {
                    return url;
                } else {
                    throw new IllegalStateException("path value : " + pathValPlaceholder + " required");
                }
            }

            StringBuilder sb = new StringBuilder();
            String res = url;

            // handle path
            if (!emptyPaths) {
                for (String key : requestPaths.keySet()) {
                    if (pathValPlaceholder.contains(key)) {
                        Object val = requestPaths.get(key);
                        if (Objects.isNull(val) && !autoMapParamToPath) {
                            throw new IllegalStateException("path value : {" + key + "} required");
                        } else {
                            res = res.replace("{" + key + "}", toParamStr(val));
                            // consume placeholder
                            pathValPlaceholder.remove(key);
                        }
                    }
                }
            }

            sb.append("?");

            // handle param
            if (!emptyParams) {
                for (String key : requestParams.keySet()) {
                    // handle surplus path if function open
                    if (autoMapParamToPath) {
                        if (pathValPlaceholder.contains(key)) {
                            Object val = requestParams.get(key);
                            if (Objects.isNull(val)) {
                                throw new IllegalArgumentException("path value : {" + key + "} required");
                            } else {
                                res = res.replace("{" + key + "}", toParamStr(val));
                                // consume placeholder
                                pathValPlaceholder.remove(key);
                            }
                            continue;
                        }
                    }
                    // do handle param
                    Object val = requestParams.get(key);
                    if (Objects.isNull(val)) {
                        continue;
                    }
                    sb.append(key).append("=").append(toParamStr(val)).append("&");
                }
            }

            // check path has fill complete
            if (!pathValPlaceholder.isEmpty()) {
                throw new IllegalStateException("path value : " + pathValPlaceholder + " required");
            }

            int andIndex = sb.lastIndexOf("&");
            if (andIndex != -1) {
                sb.deleteCharAt(andIndex);
            }
            return res + sb;
        }

        /**
         * 如果是迭代器或者数组 就用逗号拼接
         * 其他就toString
         */
        @SuppressWarnings("rawtypes")
        private static String toParamStr(Object val) {
            String value;
            if (val instanceof Iterable) {
                Iterable it = (Iterable) val;
                StringBuilder valSb = new StringBuilder();
                for (Object o : it) {
                    valSb.append(o.toString()).append(",");
                }
                value = valSb.deleteCharAt(valSb.lastIndexOf(",")).toString();
            } else if (val.getClass().isArray()) {
                value = Arrays.stream((Object[]) val)
                        .map(Object::toString)
                        .collect(Collectors.joining(","));
            } else {
                value = val.toString();
            }
            return value;
        }

        private <T> MultiValueMap<String, T> apply(IN in, MultiValueMap<String, Function<IN, T>> target) {
            if (empty(target)) {
                return null;
            }
            MultiValueMap<String, T> res = new LinkedMultiValueMap<>(target.size());
            target.forEach((key, value) -> {
                List<T> values = value.stream()
                        .map(func -> func.apply(in))
                        .collect(Collectors.toList());
                res.addAll(key, values);
            });
            return res;
        }

        /**
         * extract raw data to the map container
         *
         * @param in      raw data
         * @param funcMap map function
         * @param <T>     T
         * @return map
         */
        private <T> Map<String, T> apply(IN in, Map<String, Function<IN, T>> funcMap) {
            if (empty(funcMap)) {
                return null;
            }
            Map<String, T> res = new HashMap<>(funcMap.size());
            funcMap.forEach((key, value) -> res.put(key, value.apply(in)));
            return res;
        }

        private static boolean empty(Map<String, ?> target) {
            return null == target || target.isEmpty();
        }

        private static boolean empty(Set<?> target) {
            return null == target || target.isEmpty();
        }

    }

    class BuilderEditor<IN, OUT> extends Builder<IN, OUT> {

        private static <IN, OUT> BuilderEditor<IN, OUT> clone(Builder<IN, OUT> ref) {
            return new BuilderEditor<>(ref);
        }

        private BuilderEditor(Builder<IN, OUT> ref) {
            super(ref.reqClass, ref.respClass);
            // copy column
            super.url = ref.url;
            super.method = ref.method;
            super.path = ref.path != null ? new HashMap<>(ref.path) : null;
            super.param = ref.param != null ? new HashMap<>(ref.param) : null;
            super.header = ref.header != null ? new LinkedMultiValueMap<>(ref.header) : null;
            super.body = ref.body;
            super.pathValPlaceholder = ref.pathValPlaceholder != null ? new HashSet<>(ref.pathValPlaceholder) : null;
            super.client = ref.client != null ? ref.client : DEFAULT_CLIENT;
            super.formData = ref.formData;
            super.log = ref.log;
            super.autoMapParamToPath = ref.autoMapParamToPath;
        }

        public BuilderEditor<IN, OUT> disableLog() {
            super.log = false;
            return this;
        }

        public BuilderEditor<IN, OUT> disableFormData() {
            super.formData = false;
            return this;
        }

        public BuilderEditor<IN, OUT> enableAutoMapParamToPath() {
            super.autoMapParamToPath = true;
            return this;
        }

        public BuilderEditor<IN, OUT> removeHeader(String key) {
            super.header.remove(key);
            return this;
        }

        public BuilderEditor<IN, OUT> removeParam(String key) {
            super.param.remove(key);
            return this;
        }

        public BuilderEditor<IN, OUT> removePath(String key) {
            super.path.remove(key);
            return this;
        }

    }
}

demo

    public static void main(String[] args) {
        Api<String, String> test = Api.builder(String.class, String.class)
                .method(HttpMethod.GET)
                .url("https://www.baidu.com/{path}")
                .path("path", in -> in)
                .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
                .param("timestamp", System.currentTimeMillis())
                .enableLog()
                .client(Api.Builder.DEFAULT_CLIENT)
                .build();
        test.apply("测试");
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
spring-core.jar(必须):这个jar 文件包含Spring 框架基本的核心工具类。Spring 其它组件要都要使用到这个包里的类,是其它组件的基本核心,当然你也可以在自己的应用系统中使用这些工具类。 外部依赖Commons Logging, (Log4J)。 spring-beans.jar(必须):这 个jar 文件是所有应用都要用到的,它包含访问配置文件、创建和管理bean 以及进行Inversion of Control / Dependency Injection(IoC/DI)操作相关的所有类。如果应用只需基本的IoC/DI 支持,引入spring-core.jar 及spring-beans.jar 文件就可以了。 外部依赖spring-core,(CGLIB)。 spring-aop.jar(必须):这个jar 文件包含在应用中使用Spring 的AOP 特性时所需的类和源码级元数据支持。使用基于AOP 的Spring特性,如声明型事务管理(Declarative Transaction Management),也要在应用里包含这个jar包。 外部依赖spring-core, (spring-beans,AOP Alliance, CGLIB,Commons Attributes)。 spring-context.jar(必须):这个jar 文件在基础IOC功能上为Spring 核心提供了大量扩展服务,此外还提供许多企业级服务的支持,有邮件服务、任务调度、JNDI定位,EJB集成、远程访问、缓存以及多种视图层框架的支持。可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI 所需的全部类,instrumentation组件以及校验Validation 方面的相关类。 外部依赖spring-beans, (spring-aop)。 spring-jdbc.jar(必须) :这个jar 文件包含对Spring 对JDBC 数据访问进行封装的所有类。 外部依赖spring-beans,spring-dao。 spring-web.jar(必须) :这个jar 文件包含Web 应用开发时,用到Spring 框架时所需的核心类,包括自动载入Web Application Context 特性的类、Struts 与JSF 集成类、文件上传的支持类、Filter 类和大量工具辅助类。 外部依赖spring-context, Servlet API, (JSP API, JSTL, Commons FileUpload, COS)。 spring-webmvc.jar :这个jar 文件包含Spring MVC 框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、Tiles、Velocity、XSLT相关类。包括框架的Servlets,Web MVC框架,控制器和视图支持。当然,如果你的应用使用了独立的MVC 框架,则无需这个JAR 文件里的任何类。 外部依赖spring-web, (spring-support,Tiles,iText,POI)。 spring-aspects.jar :提供对AspectJ的支持,以便可以方便的将面向方面的功能集成进IDE中,比如Eclipse AJDT。 spring-context-support.jar:Spring context的扩展支持,用于MVC方面。 spring-expression.jar:Spring表达式语言。 spring-instrument.jar:Spring对服务器的代理接口 spring-instrument-tomcat.jar:Spring对tomcat连接池的集成 spring-jms.jar:为简化jms api的使用而做的简单封装。 外部依赖spring-beans,spring-dao,JMS APIspring-orm.jar:整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现 spring-oxm.jar:Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换 spring-messaging.jar: spring-test.jar:对JUNIT等测试框架的简单封装 spring-tx.jar:为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。 spring-webmvc-portlet.jar:Spring MVC的增强 spring-websocket.jar:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值