如何在Spring Boot中使用带有休息模板的多部分表单数据

时间:2019-07-30 09:44:36

标签: java spring-boot resttemplate

我使用以下代码来消耗USE THIS IMAGE LOADER EXTENSION let imageCache = NSCache<AnyObject, AnyObject>() class ImageLoader: UIImageView { var imageURL: URL? let activityIndicator = UIActivityIndicatorView() func loadImageWithUrl(_ url: URL) { // setup activityIndicator... activityIndicator.color = .darkGray addSubview(activityIndicator) activityIndicator.translatesAutoresizingMaskIntoConstraints = false activityIndicator.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true activityIndicator.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true imageURL = url image = nil activityIndicator.startAnimating() // retrieves image if already available in cache if let imageFromCache = imageCache.object(forKey: url as AnyObject) as? UIImage { self.image = imageFromCache activityIndicator.stopAnimating() return } // image does not available in cache.. so retrieving it from url... URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in if error != nil { print(error as Any) self.activityIndicator.stopAnimating() return } DispatchQueue.main.async(execute: { if let unwrappedData = data, let imageToCache = UIImage(data: unwrappedData) { if self.imageURL == url { self.image = imageToCache } imageCache.setObject(imageToCache, forKey: url as AnyObject) } self.activityIndicator.stopAnimating() }) }).resume() } } ** design controller ** import UIKit class ImageController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { private let cellId = "cellId" lazy var imagesSliderCV: UICollectionView = { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .vertical let cv = UICollectionView(frame: .zero, collectionViewLayout: layout) cv.translatesAutoresizingMaskIntoConstraints = false cv.backgroundColor = .white cv.showsHorizontalScrollIndicator = false cv.delegate = self cv.dataSource = self cv.isPagingEnabled = true cv.register(ImageSliderCell.self, forCellWithReuseIdentifier: self.cellId) return cv }() // // Mark:- CollectionView Methods........ // var arrURLs = [ "https://homepages.cae.wisc.edu/~ece533/images/airplane.png", "https://homepages.cae.wisc.edu/~ece533/images/arctichare.png", "https://homepages.cae.wisc.edu/~ece533/images/baboon.png", "https://homepages.cae.wisc.edu/~ece533/images/barbara.png", "https://homepages.cae.wisc.edu/~ece533/images/boat.png", "https://homepages.cae.wisc.edu/~ece533/images/cat.png", "https://homepages.cae.wisc.edu/~ece533/images/fruits.png", "https://homepages.cae.wisc.edu/~ece533/images/frymire.png", "https://homepages.cae.wisc.edu/~ece533/images/girl.png", "https://homepages.cae.wisc.edu/~ece533/images/goldhill.png", "https://homepages.cae.wisc.edu/~ece533/images/lena.png", "https://homepages.cae.wisc.edu/~ece533/images/monarch.png", "https://homepages.cae.wisc.edu/~ece533/images/mountain.png", "https://homepages.cae.wisc.edu/~ece533/images/peppers.png", "https://homepages.cae.wisc.edu/~ece533/images/pool.png", "https://homepages.cae.wisc.edu/~ece533/images/sails.png", "https://homepages.cae.wisc.edu/~ece533/images/serrano.png", "https://homepages.cae.wisc.edu/~ece533/images/tulips.png", "https://homepages.cae.wisc.edu/~ece533/images/watch.png", "https://homepages.cae.wisc.edu/~ece533/images/zelda.png" ] func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return arrURLs.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! ImageSliderCell let ImagePath = arrURLs[indexPath.item] if let strUrl = ImagePath.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed), let imgUrl = URL(string: strUrl) { cell.frontImg.loadImageWithUrl(imgUrl) } return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: screenWidth, height: 288) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return 0 } func setupAutoLayout(){ NSLayoutConstraint.activate([ imagesSliderCV.leftAnchor.constraint(equalTo: view.leftAnchor), imagesSliderCV.rightAnchor.constraint(equalTo: view.rightAnchor), imagesSliderCV.topAnchor.constraint(equalTo: view.topAnchor), imagesSliderCV.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) } } **collectionView cell ** import UIKit class ImageSliderCell: UICollectionViewCell { // let frontImg: ImageLoader = { let img = ImageLoader() img.translatesAutoresizingMaskIntoConstraints = false img.contentMode = .scaleAspectFill img.clipsToBounds = true return img }() // override init(frame: CGRect) { super.init(frame: frame) addSubview(frontImg) setupAutolayout() } func setupAutolayout(){ frontImg.leftAnchor.constraint(equalTo: leftAnchor, constant: 8).isActive = true frontImg.rightAnchor.constraint(equalTo: rightAnchor, constant: -8).isActive = true frontImg.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = true frontImg.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8).isActive = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } } 。但是我无法为文件指定multipart/form-data。春季如何传递content-type,文件名,文件名内容?

content-type

我使用MultiValueMap添加文件名及其内容,但我无法传递文件的内容类型。     执行时,我收到400错误请求。你可以在这里帮忙吗?

我以前尝试过以下方法,这里也收到了400个错误请求。这里需要帮助。

HttpHeaders header = new HttpHeaders();
header.add("Token", "_45378ffb-e366-45ec-9ac4-eb968c57aee3");   header.setContentType(MediaType.MULTIPART_FORM_DATA);

MultiValueMap<String, Object> fileMap = new LinkedMultiValueMap<>();
fileMap.add(filename, msg.getBytes());
fileMap.add("OrderRequest", message);

HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(fileMap, header);

ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity,String.class);

2 个答案:

答案 0 :(得分:0)

准备文件部分

<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var m = 10,
r = 100,
z = d3.scale.category20c();

var pie = d3.layout.pie()
.value(function(d) { return +d.qty; })
.sort(function(a, b) { return b.qty - a.qty;});

然后准备消息部分

HttpHeaders filePartHeaders = new HttpHeaders();
filePartHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
HttpEntity filePart = new HttpEntity<>(new ByteArrayResource(msg.getBytes()) {
    @Override
    public String getFilename() {
        return filename;
    }
}, filePartHeaders);

然后将各个部分组合成一个多部分请求实体

HttpHeaders messagePartHeaders = new HttpHeaders();
messagePartHeaders.setContentType(MediaType.TEXT_PLAIN);
HttpEntity messagePart = new HttpEntity<>(message, messagePartHeaders);

最后执行请求

HttpHeaders header = new HttpHeaders();
header.add("Token", "_45378ffb-e366-45ec-9ac4-eb968c57aee3");
header.setContentType(MediaType.MULTIPART_FORM_DATA);

MultiValueMap<String, Object> multiMap = new LinkedMultiValueMap<>();
multiMap.add(filename, filePart);
multiMap.add("OrderRequest", messagePart);

HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(multiMap, header);

答案 1 :(得分:0)

谢谢你, 我尝试过,但再次收到400错误请求。在这里,我使用了tcpdump并得到了这样的响应:

POST XXXXXXXXXXXXXXXXXXXXX
Accept: text/plain, application/json, application/*+json, */*
Content-Type: multipart/form-data;charset=UTF-8;boundary=XXXXXXXXXXXXXXXX
Token: XXXXXXXXXXXXXXXXXXXXXXXXXXX
User-Agent: Java/1.8.0_201
Host: XXXXXXXXXXXXXXXXXXXXXXXXXX
Connection: keep-alive
Content-Length: 1003

�bA]fG
�k�?A�--XXXXXXXXXXXXXXXXXXXX
Content-Disposition: form-data; name=filename; filename=fileName
Content-Type: application/octet-stream
Content-Length: 511

MSH|^~\&|GHHHH v2012007|HL93765411|GHH|DHM|20170725121244||ORM^O01|ghjk09876|P|2.3.1|6||AL|NE|AU|||
PID|1|||11057^^^GPC Test Practice^MR^GPC Test Practice|XXX^XXX^^^jjj^^L||19920321|F|||188 HEIGHTS DR^^ROBINA^QLD^4226^^C|||^ORN^PH^^^^04
01817188^||||||||||||||||
PV1|1|O||||||2121331W^BHAR^NAV^^^MR.^^^AUSHICPR|2121331W^BHAR^NAV^^^MR.^^^AUSHICPR|||||||||||
ORC|NW|10188-1||10188||||||||^Admin^Mr.
OBR|1|10188-1||T001^Histopathology^LN|||201707251212||||L|||||^Admin^Mr.||||||||LAB
BLG||F
--XXXXXXXXXXXXXXXXXX
Content-Disposition: form-data; name="FileName1"
Content-Type: application/json
Content-Length: 133

{"client_software_version":"XXX","batch_id":"XXXXX","order_files_sent":["fileName"],"client_software_name":"XXXXX"}
--XXXXXXXXXXXX--

以下响应是其余模板的预期响应。在这里需要帮助。     对于下面的tcpdump响应和我们不使用rest模板而获得的响应,它的工作方式是:

POST XXXXXXXXXXXXXXXXX
token: XXXXXXXXXXXXXXXXXXXXXXXXXX
content-type: multipart/form-data; boundary="---boundary"
Content-Length: 940
Host: XXXXXXXXXXXXXXXXXXXXXXXXXXXX
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.3 (Java/1.8.0_201)
Accept-Encoding: gzip,deflate

-----boundary
Content-Disposition: form-data; name="fileName"; filename="fileName"
Content-Type: application/octet-stream

MSH|^~\&|GHHHH v2012007|HL93765411|GHH|DHM|20170725121244||ORM^O01|ghjk09876|P|2.3.1|6||AL|NE|AU|||
PID|1|||11057^^^GPC Test Practice^MR^GPC Test Practice|XXX^XXX^^^jjj^^L||19920321|F|||188 HEIGHTS DR^^ROBINA^QLD^4226^^C|||^ORN^PH^^^^04
01817188^||||||||||||||||
PV1|1|O||||||2121331W^BHAR^NAV^^^MR.^^^AUSHICPR|2121331W^BHAR^NAV^^^MR.^^^AUSHICPR|||||||||||
ORC|NW|10188-1||10188||||||||^Admin^Mr.
OBR|1|10188-1||T001^Histopathology^LN|||201707251212||||L|||||^Admin^Mr.||||||||LAB
BLG||F
-----boundary
Content-Disposition: form-data; name="filename1"; filename="filename1"
Content-Type: application/json; charset=UTF-8

{"client_software_version":"XXX","batch_id":"XXXXX","order_files_sent":["fileName"],"client_software_name":"XXXXX"}
-----boundary--