RestTemplate OR Spring Cloud Feign 上传文件
SpringBoot,通过RestTemplate 或者 Spring Cloud Feign,上传文件(支持多文件上传),服务端接口是MultipartFile接收。
将文件的字节流,放入ByteArrayResource中,并重写getFilename方法。
然后将ByteArrayResource放入MultiValueMap中(如果是Feign调用,方法里传参就是MultiValueMap),
然后进行上传时,Spring会自动识别到Map中的文件数据,然后通过FormHttpMessageConverter,将数据转成form表单型的multipart/formdata请求。
这里有个坑!
Spring web 4里面的FormHttpMessageConverter在将文件转成formdata时,会将文件名转成Byte[],但是使用的编码却是写死 US-ASCII,该编码不支持中文,使用该编码转换后,中文变成?号,是无法转回来的。
我想到的解决方法:
1.将spring版本升到5,Spring5里面,该编码是可以传入修改的。Springboot,默认UTF8
2.客户端进行一次编码,比如URLEncoder。然后服务端进行Decoder。
贴部分代码:
Feign
调用方,使用Spring 的MultiValueMap类,将文件File 转成 Resource,如果多个文件,则可以循环 用 add 方法,放入一个key下。
MultiValueMap是允许一key多值的。
或者,将多个Resource放入list,然后将list put 进 map中。
接收方
接收,可以用
(MultiValueMap map)
如果有其他的 值。
则是(MultiValueMap map,String XXX,String AAA)
多文件,则是
(MultiValueMap[] map,String XXX,String AAA)
或者用对象接收,也可以,不需要 @RequestBody 注解,这个注解是接收 http body里的json的。
(Bean bean),bean对象里,则是 MultiValueMap[] map,String XXX,String AAA
====================== 分割线 =================================
我在查询Feign上传文件时,还查到了另一种方式,就是专门给Feign方式提供的feign form相关Jar包,
引入Jar包后,然后进行相关配置,便可以在Feign方法中,参数直接传递MultipartFile。
该方法,或许也可以解决Spring4的编码问题。
=================== 分隔线:2018-11-8补充 关于 feign form用法 ====================
先引入相关jar:
- <dependency>
- <groupId>io.github.openfeign.form</groupId>
- <artifactId>feign-form</artifactId>
- <version>3.2.2</version>
- </dependency>
- <dependency>
- <groupId>io.github.openfeign.form</groupId>
- <artifactId>feign-form-spring</artifactId>
- <version>3.2.2</version>
- </dependency>
- @Bean
- public Logger.Level feignLoggerLevel() {
- return Logger.Level.FULL;
- }
- @Bean
- public Encoder feignFormEncoder() {
- return new SpringFormEncoder();
- }
feign 调用方法 写法 :
- save(@RequestPart MultipartFile file,@RequestParam("khbh") String khbh)
- 但是如果,参数多时,一个一个写较为麻烦,可以用
- save(Map<String,?> param)
- 但是,经过测试,发现如果 map中value是null,会出现异常。(原因好像是因为,在将 值写入 formdata时,没有null判断)
- ========== 上面的用的 feign form
- 下面 有从网络上查到的,是类似于 feign form的解决方式:
http://b-l-east.iteye.com/blog/2373462
- 糞坑-SpringCloud中使用Feign的坑
- 示例如下:
- @FeignClient("service-resource")
- //@RequestMapping("/api/test")
- public interface TestResourceItg {
- @RequestMapping(value = "/api/test/raw", method = RequestMethod.POST, consumes = "application/x-www-form-urlencoded")
- public String raw1(@PathVariable("subject") String subject, // 标题
- @RequestParam("content") String content); // 内容
- }
- 说明:
- *使用RequestMapping中的consumes指定生成的请求的Content-Type
- *RequestParam指定的参数会拼接在URL之后,如: ?name=xxx&age=18
- *PathVariable指定的参数会放到一个LinkedHashMap<String, ?>传入到feign的Encoder中进行处理,而在Spring中实现了该接口的Encoder为SpringEncoder,而该实现又会使用Spring中的HttpMessageConverter进行请求体的写入。
- 坑:
- *不要在接口类名上使用RequestMapping,虽然可以使用,但同时SpringMVC会把该接口的实例当作Controller开放出去,这个可以在启动的Mapping日志中查看到
- *使用默认的SpringEncoder,在不指定consumes时,PathVariable中的参数会生成JSON字符串发送,且默认情况下不支持Form表单的生成方式,原因为:FormHttpMessageConverter只能处理MultiValueMap,而使用PathVariable参数被放在了HashMap中。默认更不支持文件上传。其实已经有支持处理各种情况的HttpMessageConverter存在。
- 填坑:
- *支持Form表单提交:只需要编写一个支持Map的FormHttpMessageConverter即可,内部可调用FormHttpMessageConverter的方法简化操作。
- *支持文件上传:只需要把要上传的文件封装成一个Resource(该Resource一定要实现filename接口,这个是把请求参数解析成文件的标识),使用默认的ResourceHttpMessageConverter处理即可。
- *支持处理MultipartFile参数:编写一个支持MultipartFile的MultipartFileHttpMessageConverter即可,内部可调用ResourceHttpMessageConverter实现,同时注意需要将其添加至FormHttpMessageConverter的Parts中,并重写FormHttpMessageConverter的getFilename方法支持从MultipartFile中获取filename
- *所有的HttpMessageConverter直接以@Bean的方式生成即可,spring会自动识别添加
- 完美支持表单和文件上传:
- 方案一:
- 使用附件中的MapFormHttpMessageConverter.java和MultipartFileHttpMessageConverter.java
- 在Spring中进行如下配置即可
- @Bean
- public MapFormHttpMessageConverter mapFormHttpMessageConverter(MultipartFileHttpMessageConverter multipartFileHttpMessageConverter) {
- MapFormHttpMessageConverter mapFormHttpMessageConverter = new MapFormHttpMessageConverter();
- mapFormHttpMessageConverter.addPartConverter(multipartFileHttpMessageConverter);
- return mapFormHttpMessageConverter;
- }
- @Bean
- public MultipartFileHttpMessageConverter multipartFileHttpMessageConverter() {
- return new MultipartFileHttpMessageConverter();
- }
- 方案二:
- 使用FeignSpringFormEncoder.java
- 在Spring中配置如下:
- @Bean
- public Encoder feignEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
- return new FeignSpringFormEncoder(messageConverters);
- }
- 推荐使用方案一
- 方案二为参考https://github.com/pcan/feign-client-test而来,未测
上面方案中所用代码,贴在下面:
- package com.access.service.saas.cmpt.utl;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- import org.springframework.core.io.InputStreamResource;
- import org.springframework.http.HttpInputMessage;
- import org.springframework.http.HttpOutputMessage;
- import org.springframework.http.MediaType;
- import org.springframework.http.converter.HttpMessageConverter;
- import org.springframework.http.converter.HttpMessageNotReadableException;
- import org.springframework.http.converter.HttpMessageNotWritableException;
- import org.springframework.http.converter.ResourceHttpMessageConverter;
- import org.springframework.web.multipart.MultipartFile;
- /**
- * @author elvis.xu
- * @since 2017-05-09 11:17
- */
- public class MultipartFileHttpMessageConverter implements HttpMessageConverter<MultipartFile> {
- protected List<MediaType> supportedMediaTypes = new ArrayList<MediaType>();
- protected ResourceHttpMessageConverter resourceHttpMessageConverter;
- public MultipartFileHttpMessageConverter() {
- supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
- resourceHttpMessageConverter = new ResourceHttpMessageConverter();
- }
- public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) {
- this.supportedMediaTypes = supportedMediaTypes;
- }
- @Override
- public List<MediaType> getSupportedMediaTypes() {
- return Collections.unmodifiableList(this.supportedMediaTypes);
- }
- @Override
- public boolean canRead(Class<?> clazz, MediaType mediaType) {
- return false;
- }
- @Override
- public boolean canWrite(Class<?> clazz, MediaType mediaType) {
- if (!MultipartFile.class.isAssignableFrom(clazz)) {
- return false;
- }
- if (mediaType == null || MediaType.ALL.equals(mediaType)) {
- return true;
- }
- for (MediaType supportedMT : getSupportedMediaTypes()) {
- if (supportedMT.isCompatibleWith(mediaType)) {
- return true;
- }
- }
- return false;
- }
- @Override
- public MultipartFile read(Class<? extends MultipartFile> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
- return null;
- }
- @Override
- public void write(MultipartFile file, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
- MultipartFileResource multipartFileResource = new MultipartFileResource(file);
- resourceHttpMessageConverter.write(multipartFileResource, contentType, outputMessage);
- }
- public static class MultipartFileResource extends InputStreamResource {
- private final String filename;
- private final long size;
- public MultipartFileResource(MultipartFile multipartFile) throws IOException {
- this(multipartFile.getOriginalFilename(), multipartFile.getSize(), multipartFile.getInputStream());
- }
- public MultipartFileResource(String filename, long size, InputStream inputStream) {
- super(inputStream);
- this.size = size;
- this.filename = filename;
- }
- @Override
- public String getFilename() {
- return this.filename;
- }
- @Override
- public InputStream getInputStream() throws IOException, IllegalStateException {
- return super.getInputStream(); //To change body of generated methods, choose Tools | Templates.
- }
- @Override
- public long contentLength() throws IOException {
- return size;
- }
- }
- }
- package com.access.service.saas.cmpt.utl;
- import java.io.ByteArrayOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.lang.reflect.Type;
- import java.nio.charset.Charset;
- import java.util.Arrays;
- import java.util.List;
- import java.util.Map;
- import feign.RequestTemplate;
- import feign.codec.EncodeException;
- import org.springframework.beans.factory.ObjectFactory;
- import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
- import org.springframework.cloud.netflix.feign.support.SpringEncoder;
- import org.springframework.core.io.InputStreamResource;
- import org.springframework.core.io.Resource;
- import org.springframework.http.HttpEntity;
- import org.springframework.http.HttpHeaders;
- import org.springframework.http.HttpOutputMessage;
- import org.springframework.http.MediaType;
- import org.springframework.http.converter.HttpMessageConverter;
- import org.springframework.util.LinkedMultiValueMap;
- import org.springframework.web.multipart.MultipartFile;
- /**
- * @author elvis.xu
- * @since 2017-04-11 15:33
- */
- public class FeignSpringFormEncoder extends SpringEncoder {
- protected ObjectFactory<HttpMessageConverters> messageConverters;
- protected HttpHeaders multipartHeaders = new HttpHeaders();
- public static final Charset UTF_8 = Charset.forName("UTF-8");
- public FeignSpringFormEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
- super(messageConverters);
- this.messageConverters = messageConverters;
- multipartHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
- }
- protected static boolean isFormRequest(Type type) {
- return MAP_STRING_WILDCARD.equals(type);
- }
- protected static boolean isMultipart(Object body, Type bodyType) {
- if (isFormRequest(bodyType)) {
- Map<String, ?> map = (Map<String, ?>) body;
- for (Map.Entry<String, ?> entry : map.entrySet()) {
- Object value = entry.getValue();
- if (isMultipartFile(value) || isMultipartFileArray(value)) {
- return true;
- }
- }
- }
- return false;
- }
- protected static boolean isMultipartFile(Object obj) {
- return obj instanceof MultipartFile;
- }
- protected static boolean isMultipartFileArray(Object o) {
- return o != null && o.getClass().isArray() && MultipartFile.class.isAssignableFrom(o.getClass().getComponentType());
- }
- @Override
- public void encode(Object requestBody, Type bodyType, RequestTemplate request) throws EncodeException {
- if (isMultipart(requestBody, bodyType)) {
- encodeMultipartFormRequest((Map<String, ?>) requestBody, request);
- } else {
- super.encode(requestBody, bodyType, request);
- }
- }
- /**
- * Encodes the request as a multipart form. It can detect a single {@link MultipartFile}, an
- * array of {@link MultipartFile}s, or POJOs (that are converted to JSON).
- *
- * @param formMap
- * @param template
- * @throws EncodeException
- */
- private void encodeMultipartFormRequest(Map<String, ?> formMap, RequestTemplate template) throws EncodeException {
- if (formMap == null) {
- throw new EncodeException("Cannot encode request with null form.");
- }
- LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
- for (Map.Entry<String, ?> entry : formMap.entrySet()) {
- Object value = entry.getValue();
- if (isMultipartFile(value)) {
- map.add(entry.getKey(), encodeMultipartFile((MultipartFile) value));
- } else if (isMultipartFileArray(value)) {
- encodeMultipartFiles(map, entry.getKey(), Arrays.asList((MultipartFile[]) value));
- } else {
- map.add(entry.getKey(), encodeJsonObject(value));
- }
- }
- encodeRequest(map, multipartHeaders, template);
- }
- /**
- * Wraps a single {@link MultipartFile} into a {@link HttpEntity} and sets the
- * {@code Content-type} header to {@code application/octet-stream}
- *
- * @param file
- * @return
- */
- private HttpEntity<?> encodeMultipartFile(MultipartFile file) {
- HttpHeaders filePartHeaders = new HttpHeaders();
- filePartHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
- try {
- Resource multipartFileResource = new MultipartFileResource(file.getOriginalFilename(), file.getSize(), file.getInputStream());
- return new HttpEntity<>(multipartFileResource, filePartHeaders);
- } catch (IOException ex) {
- throw new EncodeException("Cannot encode request.", ex);
- }
- }
- /**
- * Fills the request map with {@link HttpEntity}s containing the given {@link MultipartFile}s.
- * Sets the {@code Content-type} header to {@code application/octet-stream} for each file.
- *
- * @param map the current request map.
- * @param name the name of the array field in the multipart form.
- * @param files
- */
- private void encodeMultipartFiles(LinkedMultiValueMap<String, Object> map, String name, List<? extends MultipartFile> files) {
- HttpHeaders filePartHeaders = new HttpHeaders();
- filePartHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
- try {
- for (MultipartFile file : files) {
- Resource multipartFileResource = new MultipartFileResource(file.getOriginalFilename(), file.getSize(), file.getInputStream());
- map.add(name, new HttpEntity<>(multipartFileResource, filePartHeaders));
- }
- } catch (IOException ex) {
- throw new EncodeException("Cannot encode request.", ex);
- }
- }
- /**
- * Wraps an object into a {@link HttpEntity} and sets the {@code Content-type} header to
- * {@code application/json}
- *
- * @param o
- * @return
- */
- private HttpEntity<?> encodeJsonObject(Object o) {
- HttpHeaders jsonPartHeaders = new HttpHeaders();
- jsonPartHeaders.setContentType(MediaType.APPLICATION_JSON);
- return new HttpEntity<>(o, jsonPartHeaders);
- }
- /**
- * Calls the conversion chain actually used by
- * {@link org.springframework.web.client.RestTemplate}, filling the body of the request
- * template.
- *
- * @param value
- * @param requestHeaders
- * @param template
- * @throws EncodeException
- */
- private void encodeRequest(Object value, HttpHeaders requestHeaders, RequestTemplate template) throws EncodeException {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- HttpOutputMessage dummyRequest = new HttpOutputMessageImpl(outputStream, requestHeaders);
- try {
- Class<?> requestType = value.getClass();
- MediaType requestContentType = requestHeaders.getContentType();
- for (HttpMessageConverter<?> messageConverter : messageConverters.getObject().getConverters()) {
- if (messageConverter.canWrite(requestType, requestContentType)) {
- ((HttpMessageConverter<Object>) messageConverter).write(value, requestContentType, dummyRequest);
- break;
- }
- }
- } catch (IOException ex) {
- throw new EncodeException("Cannot encode request.", ex);
- }
- HttpHeaders headers = dummyRequest.getHeaders();
- if (headers != null) {
- for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
- template.header(entry.getKey(), entry.getValue());
- }
- }
- /*
- we should use a template output stream... this will cause issues if files are too big,
- since the whole request will be in memory.
- */
- template.body(outputStream.toByteArray(), UTF_8);
- }
- /**
- * Dummy resource class. Wraps file content and its original name.
- */
- static class MultipartFileResource extends InputStreamResource {
- private final String filename;
- private final long size;
- public MultipartFileResource(String filename, long size, InputStream inputStream) {
- super(inputStream);
- this.size = size;
- this.filename = filename;
- }
- @Override
- public String getFilename() {
- return this.filename;
- }
- @Override
- public InputStream getInputStream() throws IOException, IllegalStateException {
- return super.getInputStream(); //To change body of generated methods, choose Tools | Templates.
- }
- @Override
- public long contentLength() throws IOException {
- return size;
- }
- }
- /**
- * Minimal implementation of {@link org.springframework.http.HttpOutputMessage}. It's needed to
- * provide the request body output stream to
- * {@link org.springframework.http.converter.HttpMessageConverter}s
- */
- private class HttpOutputMessageImpl implements HttpOutputMessage {
- private final OutputStream body;
- private final HttpHeaders headers;
- public HttpOutputMessageImpl(OutputStream body, HttpHeaders headers) {
- this.body = body;
- this.headers = headers;
- }
- @Override
- public OutputStream getBody() throws IOException {
- return body;
- }
- @Override
- public HttpHeaders getHeaders() {
- return headers;
- }
- }
- }
- package com.access.service.saas.cmpt.utl;
- import java.io.IOException;
- import java.util.List;
- import java.util.Map;
- import org.springframework.http.HttpInputMessage;
- import org.springframework.http.HttpOutputMessage;
- import org.springframework.http.MediaType;
- import org.springframework.http.converter.FormHttpMessageConverter;
- import org.springframework.http.converter.HttpMessageConverter;
- import org.springframework.http.converter.HttpMessageNotReadableException;
- import org.springframework.http.converter.HttpMessageNotWritableException;
- import org.springframework.util.LinkedMultiValueMap;
- import org.springframework.util.MultiValueMap;
- import org.springframework.web.multipart.MultipartFile;
- /**
- * @author elvis.xu
- * @since 2017-05-09 10:58
- */
- public class MapFormHttpMessageConverter implements HttpMessageConverter<Map<String, ?>> {
- protected FormHttpMessageConverter formHttpMessageConverter;
- public MapFormHttpMessageConverter() {
- this.formHttpMessageConverter = new MultipartFormHttpMessageConverter();
- }
- public void addPartConverter(HttpMessageConverter<?> partConverter) {
- this.formHttpMessageConverter.addPartConverter(partConverter);
- }
- @Override
- public boolean canRead(Class<?> clazz, MediaType mediaType) {
- return formHttpMessageConverter.canRead(clazz, mediaType);
- }
- @Override
- public List<MediaType> getSupportedMediaTypes() {
- return formHttpMessageConverter.getSupportedMediaTypes();
- }
- @Override
- public boolean canWrite(Class<?> clazz, MediaType mediaType) {
- if (!Map.class.isAssignableFrom(clazz)) {
- return false;
- }
- if (mediaType == null || MediaType.ALL.equals(mediaType)) {
- return true;
- }
- for (MediaType supportedMediaType : getSupportedMediaTypes()) {
- if (supportedMediaType.isCompatibleWith(mediaType)) {
- return true;
- }
- }
- return false;
- }
- @Override
- public Map<String, ?> read(Class<? extends Map<String, ?>> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
- return formHttpMessageConverter.read(null, inputMessage);
- }
- public void write(Map<String, ?> map, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
- MultiValueMap<String, Object> multiMap = null;
- if (map != null) {
- if (map instanceof MultiValueMap) {
- multiMap = (MultiValueMap<String, Object>) map;
- } else {
- multiMap = new LinkedMultiValueMap<>();
- for (Map.Entry<String, ?> entry : map.entrySet()) {
- multiMap.add(entry.getKey(), entry.getValue());
- }
- }
- }
- formHttpMessageConverter.write(multiMap, contentType, outputMessage);
- }
- public static class MultipartFormHttpMessageConverter extends FormHttpMessageConverter {
- @Override
- protected String getFilename(Object part) {
- String rt = super.getFilename(part);
- if (rt == null && part instanceof MultipartFile) {
- return ((MultipartFile) part).getOriginalFilename();
- }
- return null;
- }
- }
- }
RestTemplate OR Spring Cloud Feign 上传文件的更多相关文章
- spring cloud feign 上传文件报not a type supported by this encoder解决方案
上传文件调用外部服务报错: not a type supported by this encoder 查看SpringFormEncoder类的源码: public class SpringFormE ...
- spring mvc(注解)上传文件的简单例子
spring mvc(注解)上传文件的简单例子,这有几个需要注意的地方1.form的enctype=”multipart/form-data” 这个是上传文件必须的2.applicationConte ...
- spring mvc CommonsMultipartResolver上传文件异常处理
近期已经上线的项目出现了一个异常 严重: Servlet.service() for servlet JeeCmsAdmin threw exception org.apache.commons.fi ...
- springMVC+spring+hibernate注解上传文件到数据库,下载,多文件上传
数据库 CREATE TABLE `annex` ( `id` bigint() NOT NULL AUTO_INCREMENT, `realName` varchar() DEFAULT NULL, ...
- spring boot(十七)上传文件
上传文件是互联网中常常应用的场景之一,最典型的情况就是上传头像等,今天就带着带着大家做一个Spring Boot上传文件的小案例. 1.pom包配置 我们使用Spring Boot最新版本1.5.9. ...
- 利用spring的CommonsMultipartResolver上传文件
1.CommonsMultipartResolver是spring里面提供的一个上传方式,效率我不知道,但是加入spring容器管理还是很不错的. 2.先看依赖包pom.xml <project ...
- Spring使用mutipartFile上传文件报错【Failed to instantiate [org.springframework.web.multipart.MultipartFile]】
报错场景: 使用SSM框架实现文件上传时报“Failed to instantiate [org.springframework.web.multipart.MultipartFile]”错,控制器源 ...
- Spring Boot (30) 上传文件
文件上传 上传文件和下载文件是Java Web中常见的一种操作,文件上传主要是将文件通过IO流传输到服务器的某一个文件夹下. 导入依赖 在pom.xml中添加上spring-boot-starter- ...
- Spring Boot应用上传文件时报错
问题描述 Spring Boot应用(使用默认的嵌入式Tomcat)在上传文件时,偶尔会出现上传失败的情况,后台报错日志信息如下:"The temporary upload location ...
随机推荐
- 【明哥报错簿】之【 "javax.servlet.http.HttpServlet" was not found on the Java Build Path || HttpServletRequest/HttpServletResponse cannot be resolved to a type】
The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path login ...
- TCP的拥塞控制 (三)
1. Multiple Packet Losses Fast Retransmit/Fast Recovery机制可以很好地处理单个packet丢失的问题,但当大量packet同时丢包时(一个RT ...
- Spring Boot系列教程五:使用properties配置文件实现多环境配置
一.前言 实际项目开发过程中会用到多个环境,比如dev,test,product环境,不同的环境可能使用不同参数,为便于部署提高效率,本篇主要通过properties配置文件来实现多环境的配置. 二. ...
- 常州day1p3
给定一个 n 行 m 列的方格,每个格子里有一个正整数 a,1 ≤ a ≤ k,k ≤ n∗m 假设你当前时刻站在 (i,j) 这个格子里,你想要移动到 (x,y),那必须满足以下三个条件 1:i & ...
- Extjs treePanel过滤查询功能【转】
Extjs4.2中,对于treeStore中未实现filterBy函数进行实现,treestore并未继承与Ext.data.Store,对于treePanel的过滤查询功能,可有以下两种实现思路: ...
- Spring MVC @CookieValue注解
@CookieValue的作用 用来获取Cookie中的值 @CookieValue参数 1.value:参数名称 2.required:是否必须 3.defaultValue:默认值 @Cookie ...
- array_uintersect、array_uintersect_assoc、array_uintersect_uassoc 的使用方法
和 array_intersect 类似,只不过 array_uintersect* 系列函数的值比较使用自定义函数: 键的比较,array_uintersect.array_uintersect_a ...
- [ldap]slapcat/ldapsearch与ldap备份
http://serverfault.com/questions/577356/ldap-backup-with-slapcat-vs-ldapsearch Used: openldap-server ...
- uboot&kernel&system
- js知识点乱炖
修改属性 元素.style.样式=值 document.getElementById('box').style.width='200px'; 属性操作方式 1.. 的 元素.属性名如果属性是单 ...