目录
1. springboot后端
1.1 FileController.java
1.2 listener文件的ErpApplicationListener.java
1.3 【重点!】FileServiceImpl层
1.4 IFileService
1.5 StringUtil通用类
1.6 主程序加一个监听器
1.7 application.yml文件
2. 微信小程序端
2.1 TDesign的upload组件
1. app.json全局引用一下
2. wxml
3. js
1. springboot后端
1.1 FileController.java
如上图可以看到,微信小程序的请求url要传来一个type值,
controller全部代码如下,直接复制粘贴就行:
package com.huashang.controller;import com.huashang.common.BaseController;
import com.huashang.service.IFileService;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;@RestController
public class FileController extends BaseController {@Resourceprivate IFileService fileService;@RequestMapping(value = "/files/{type}", method = RequestMethod.POST)public String uploadFile(@PathVariable String type ,HttpServletRequest request) throws Exception {return fileService.uploadFiles(request, type);}}
1.2 listener文件的ErpApplicationListener.java
1.3 【重点!】FileServiceImpl层
FileServiceImpl是IFileService的实现类,先看实现类,接口放最后了
以下代码不要直接复制粘贴到serviceImpl层,是原始代码,需要修改并添加一个引用才能使用
package com.huashang.serviceImpl;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;import javax.servlet.http.HttpServletRequest;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.huashang.common.Constants;
import com.huashang.model.Alioss;
import com.huashang.service.IFileService;import cn.hutool.core.date.DateUtil;@Service
public class FileServiceImpl implements IFileService {private Alioss alioss;private final static List<String> FILE_TYPE = Arrays.asList("product", "biz", "color", "qa", "mes_qa", "oa", "model");@Autowiredpublic void setAlioss(Alioss alioss) {this.alioss = alioss;}public static OSSClient ossClient;private final static Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);@Overridepublic void initClient() {// 实例化客户端logger.info("**************************初始化阿里云文件上传服务服务端--START****************************");ossClient = new OSSClient(alioss.getEndpoint(), alioss.getAccessKeyId(), alioss.getAcceddKeySecret());logger.info("**************************初始化阿里云文件上传服务服务端--END****************************");}@Transactional@Overridepublic String uploadFiles(HttpServletRequest request, String type) throws IOException {String picUrl = "";if (request instanceof MultipartHttpServletRequest) {MultiValueMap<String, MultipartFile> multiMap = ((MultipartHttpServletRequest) request).getMultiFileMap();Set<String> keys = multiMap.keySet();for (String key : keys) {List<MultipartFile> mutiFiles = multiMap.get(key);for (int i = 0; i < mutiFiles.size(); i++) {if (!FILE_TYPE.contains(type)) {return "可以上传的文件类型:" + FILE_TYPE.toString();}MultipartFile file = mutiFiles.get(i);String originalFilename = this.getFileOldName(file);LocalDate now = LocalDate.now();String dir = type + "/" + now.getYear() + "/" + now.getMonthValue() + "/" + now.getDayOfMonth() + "/";String path = dir + originalFilename;try {ossClient.putObject(alioss.getBucketName(), path, mutiFiles.get(i).getInputStream());} catch (OSSException | ClientException | IOException e) {e.printStackTrace();}if (mutiFiles.size() - i == 1) {picUrl += "https://" + alioss.getUrl() + "/" + path;} else {picUrl += "https://" + alioss.getUrl() + "/" + path + ",";}}}}return picUrl;}@Overridepublic String uploadTmpFile(String filePath, String fileName) throws FileNotFoundException {StringBuilder dirBuilder = new StringBuilder("tmp/");dirBuilder.append(DateUtil.format(new Date(), Constants.DATE_yyyyMMdd)).append("/");StringBuilder fileLinkBuilder = new StringBuilder();fileLinkBuilder.append("https://").append(alioss.getUrl()).append("/").append(dirBuilder.toString()).append(fileName);ossClient.putObject(alioss.getBucketName(), dirBuilder.toString() + fileName, new FileInputStream(filePath + fileName));return fileLinkBuilder.toString();}private String getFileOldName(MultipartFile file) {return Objects.requireNonNull(file.getOriginalFilename()).replaceAll("[^a-zA-Z0-9.]", "^_^");}
}
接下来教大家怎么修改文件
看不清楚没关系,如下图片是你唯一需要修改的地方
以下代码直接复制粘贴到FileServiceImpl
package com.huashang.serviceImpl;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;import javax.servlet.http.HttpServletRequest;import com.huashang.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSException;
import com.huashang.common.Constants;
import com.huashang.model.Alioss;
import com.huashang.service.IFileService;import cn.hutool.core.date.DateUtil;@Service
public class FileServiceImpl implements IFileService {private Alioss alioss;private final static List<String> FILE_TYPE = Arrays.asList("product", "biz", "color", "qa", "mes_qa", "oa", "model");@Autowiredpublic void setAlioss(Alioss alioss) {this.alioss = alioss;}public static OSSClient ossClient;private final static Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);@Overridepublic void initClient() {// 实例化客户端logger.info("**************************初始化阿里云文件上传服务服务端--START****************************");ossClient = new OSSClient(alioss.getEndpoint(), alioss.getAccessKeyId(), alioss.getAcceddKeySecret());logger.info("**************************初始化阿里云文件上传服务服务端--END****************************");}@Transactional@Overridepublic String uploadFiles(HttpServletRequest request, String type) throws IOException {if(StringUtil.stringBlank(type)){throw new RuntimeException("type must not be empty");}if(!Arrays.asList("user", "house", "project").contains(type)){throw new RuntimeException("type is not supported");}StringBuilder picUrl = new StringBuilder();if (request instanceof MultipartHttpServletRequest) {MultiValueMap<String, MultipartFile> multiMap = ((MultipartHttpServletRequest) request).getMultiFileMap();Set<String> keys = multiMap.keySet();for (String key : keys) {List<MultipartFile> mutiFiles = multiMap.get(key);for (int i = 0; i < mutiFiles.size(); i++) {String fileOldName = StringUtil.getFileOldName(mutiFiles.get(i));String fileName = StringUtil.randomString(20) + fileOldName;String dir = type + "/" + DateUtil.format(new Date(), "yyMMddHH") + "/";String path = dir + fileName;try {ossClient.putObject(alioss.getBucketName(), path, mutiFiles.get(i).getInputStream());} catch (OSSException | ClientException | IOException e) {e.printStackTrace();}if (mutiFiles.size() - i == 1) {picUrl.append("https://").append(alioss.getUrl()).append("/").append(path);} else {picUrl.append("https://").append(alioss.getUrl()).append("/").append(path).append(",");}}}}return picUrl.toString();}@Overridepublic String uploadTmpFile(String filePath, String fileName) throws FileNotFoundException {StringBuilder dirBuilder = new StringBuilder("tmp/");dirBuilder.append(DateUtil.format(new Date(), Constants.DATE_yyyyMMdd)).append("/");StringBuilder fileLinkBuilder = new StringBuilder();fileLinkBuilder.append("https://").append(alioss.getUrl()).append("/").append(dirBuilder.toString()).append(fileName);ossClient.putObject(alioss.getBucketName(), dirBuilder.toString() + fileName, new FileInputStream(filePath + fileName));return fileLinkBuilder.toString();}}
1.4 IFileService
package com.huashang.service;import java.io.FileNotFoundException;
import java.io.IOException;import javax.servlet.http.HttpServletRequest;public interface IFileService {void initClient();String uploadFiles(HttpServletRequest request, String type) throws IOException;String uploadTmpFile(String filePath, String fileName) throws FileNotFoundException;
}
1.5 StringUtil通用类
都是定义好的,复制粘贴就行
package com.huashang.util;import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;@Component("stringUtil")
public class StringUtil {private static final String ALL_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";private static final String ALL_NUMBERS = "0123456789";/*** 将换行处理为空**/public static String n2Null(String myString) {if (myString == null) {return myString;}String newString = null;Pattern CRLF = Pattern.compile("(\r\n|\r|\n|\n\r)");Matcher m = CRLF.matcher(myString);if (m.find()) {newString = m.replaceAll(" ");} else {newString = myString;}return newString;}public static String randomString(int length) {StringBuffer sb = new StringBuffer();Random random = new Random();for (int i = 0; i < length; i++) {sb.append(ALL_CHARS.charAt(random.nextInt(ALL_CHARS.length())));}return sb.toString();}public static String randomNumber(int length) {StringBuffer sb = new StringBuffer();Random random = new Random();for (int i = 0; i < length; i++) {sb.append(ALL_NUMBERS.charAt(random.nextInt(ALL_NUMBERS.length())));}return sb.toString();}public static boolean stringBlank(String str) {return str == null || "".equals(str.trim());}public static String getFileOldName(MultipartFile file) {return file.getOriginalFilename().replaceAll("[^a-zA-Z0-9.]", "^_^");}public static String humb2UnderLine(String s) {if (s == null) {return null;}StringBuilder sb = new StringBuilder();boolean upperCase = false;for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);boolean nextUpperCase = true;if (i < (s.length() - 1)) {nextUpperCase = Character.isUpperCase(s.charAt(i + 1));}if (Character.isUpperCase(c)) {if (!upperCase || !nextUpperCase) {if (i > 0) {sb.append("_");}}upperCase = true;} else {upperCase = false;}sb.append(Character.toLowerCase(c));}return sb.toString();}public static String firstImage(String images) {List<String> ia = imageArray(images);return ia.isEmpty() ? null : ia.get(0);}public static List<String> imageArray(String images) {List<String> is = new ArrayList<>();for (String i : split(images, ";")) {if (!"".equals(i.trim())) {is.add(i.trim());}}return is;}public static List<String> split(String images, String splitor) {if (images == null || "".equals(images.trim())) {return new ArrayList<>();}return Arrays.asList(images.split(splitor));}public static String nullString(Object obj) {return obj == null ? "" : obj.toString();}/*** 图片的字符串,将其中的eshangying的连接替换为支持https协议的简赢域名* http://files.eshangying.com/2015-06-03/ctgge_518h0aZN0DL._UL1500_.jpg;* esyfiles.lrerp.com*/public static String dealImageEwin2Jy(String images) {if (StringUtil.stringBlank(images)) {return images;}images = images.replace("files.eshangying.com", "esyfiles.lrerp.com");return images;}/*** 将字符串text中由openToken和closeToken组成的占位符依次替换为args数组中的值** @param openToken* @param closeToken* @param text* @param args* @return*/public static String parseInner(String openToken, String closeToken, String text, Object... args) {if (args == null || args.length <= 0) {return text;}int argsIndex = 0;if (text == null || text.isEmpty()) {return "";}char[] src = text.toCharArray();int offset = 0;// search open tokenint start = text.indexOf(openToken, offset);if (start == -1) {return text;}final StringBuilder builder = new StringBuilder();StringBuilder expression = null;while (start > -1) {if (start > 0 && src[start - 1] == '\\') {// this open token is escaped. remove the backslash and continue.builder.append(src, offset, start - offset - 1).append(openToken);offset = start + openToken.length();} else {// found open token. let's search close token.if (expression == null) {expression = new StringBuilder();} else {expression.setLength(0);}builder.append(src, offset, start - offset);offset = start + openToken.length();int end = text.indexOf(closeToken, offset);while (end > -1) {if (end > offset && src[end - 1] == '\\') {// this close token is escaped. remove the backslash and continue.expression.append(src, offset, end - offset - 1).append(closeToken);offset = end + closeToken.length();end = text.indexOf(closeToken, offset);} else {expression.append(src, offset, end - offset);offset = end + closeToken.length();break;}}if (end == -1) {// close token was not found.builder.append(src, start, src.length - start);offset = src.length;} else {///仅仅修改了该else分支下的个别行代码String value = (argsIndex <= args.length - 1) ?(args[argsIndex] == null ? "" : args[argsIndex].toString()) : expression.toString();builder.append(value);offset = end + closeToken.length();argsIndex++;}}start = text.indexOf(openToken, offset);}if (offset < src.length) {builder.append(src, offset, src.length - offset);}return builder.toString();}public static String parseWith$(String text, Object... args) {return parseInner("${", "}", text, args);}public static String parse(String text, Object... args) {return parseInner("{", "}", text, args);}/*** 数组指定位置插入元素** @param after 在数组哪个元素后面 特殊: index0 代表 插入最开始* @param item 需要插入的元素* @param arr 操作的数组* @return 插入后的数组*/public static String[] arrPushItem(String after, String item, String[] arr) {ArrayList<String> list = new ArrayList<>(Arrays.asList(arr));if (after == null) {list.add(item);} else if ("index0".equals(after)) {list.add(0, item);} else {int i = list.indexOf(after) + 1;list.add(i, item);}String[] strings = new String[list.size()];list.toArray(strings);return strings;}/*** 字符串转换为BigDecimal** @param number* @return*/public static BigDecimal string2BigDecimal(String number) {if (stringBlank(number)) {return null;}return new BigDecimal(number);}public static boolean isNumeric(String str) {if (stringBlank(str)) {return false;}return str.matches("-?[0-9]+.?[0-9]*");}/*** 替换掉html 标签** @param myString* @return*/public static String filterHtml(String myString) {if (myString == null) {return myString;}String newString = myString;Pattern BREND = Pattern.compile("(<br/>|<br />|<br>|<br >)", Pattern.CASE_INSENSITIVE);Matcher me = BREND.matcher(newString);if (me.find()) {newString = me.replaceAll("\r\n");}Pattern SPANEND = Pattern.compile("(<span/>|<span />)", Pattern.CASE_INSENSITIVE);Matcher se = SPANEND.matcher(newString);if (se.find()) {newString = se.replaceAll(" ");}// 过滤html标签Pattern pHtml = Pattern.compile("<[^>]+>", Pattern.CASE_INSENSITIVE);Matcher mHtml = pHtml.matcher(newString);if (mHtml.find()) {newString = mHtml.replaceAll("");}return newString;}public static String firstToLowerCase(String str) {if (stringBlank(str)) {return str;}return str.replaceFirst(String.valueOf(str.charAt(0)), String.valueOf(str.charAt(0)).toLowerCase());}public static List<String> stringArr2List(String[] stringArr) {List<String> resultList = new ArrayList<>();if (stringArr == null) {return resultList;}for (String string : stringArr) {if (StringUtil.stringBlank(string)) {continue;}resultList.add(string);}return resultList;}public static byte[] s2BytesUTF8(String str) {if (stringBlank(str)) {return null;}return str.getBytes(StandardCharsets.UTF_8);}/*** 解码* 编码字符串 --> 文本字符串* 支持对 ASCII与UNICODE混合编码的(脏文本)字符串解码* Eg : "\"2ABRT3425\\u884C\\u653F\\u590D\\u8BAE\\u8868436FDGDSD\"" --> 2ABRT3425行政复议表** @param unicode* @return*/public static String unicodetoString(String unicode) {if (unicode == null || "".equals(unicode)) {return null;}StringBuilder sb = new StringBuilder();for (int pos = 0; pos < unicode.length(); ) {//"\"2ABRT3425\\u884C\\u653F\\u590D\\u8BAE\\u8868436FDGDSD\"";//System.out.println("pos:"+unicode.substring(pos,pos+1)+" - "+pos);//System.out.println("index:"+unicode.indexOf("\\u", pos)+"\n");if (unicode.indexOf("\\u", pos) - pos == 0) {//unicode编码 Eg: \\2435//System.out.println("pos2:"+unicode.substring(pos,pos+6));if (pos + 6 <= unicode.length()) {Character ch = (char) Integer.parseInt(unicode.substring(pos + 2, pos + 6), 16);//System.out.println("char:"+ch);sb.append(ch);pos += 6;} else {// \\usb.append(unicode, pos, pos + 2);pos += 2;}} else {//非unicode编码sb.append(unicode.charAt(pos));pos += 1;}}return sb.toString();}public static boolean integerBlank(Integer integer) {return integer == null || integer <= 0;}
}
1.6 主程序加一个监听器
package com.huashang;import com.huashang.listener.ErpApplicationListener;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;@SpringBootApplication
@EnableAsync
@EnableScheduling
@EnableTransactionManagement
@EnableAspectJAutoProxy(proxyTargetClass = true)
@MapperScan("com.huashang.mapper")
@ComponentScan("com.huashang")
public class ErpApplication {public static void main(String[] args) {SpringApplication springApplication = new SpringApplication(ErpApplication.class);// 添加监听器,执行需要在服务启动时执行的业务逻辑springApplication.addListeners(new ErpApplicationListener());springApplication.run(args);}}
1.7 application.yml文件
只需要修改一下这里就行,是你oss的配置,我这里是阿里的oss
oss是什么和怎么创建看视频就行:
如何使用OSS控制台、ossutil、ossbrowser、OSSSDK_对象存储 OSS-阿里云帮助中心 (aliyun.com)
创建好了以后,对
以上2个文件都进行以下修改
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: 'lrerp'password: 'By*****23'url: jdbc:mysql://pc-uf6fv9vxz81ws1y53.rwlb.rds.aliyuncs.com:3306/lingrong?useUnicode=yes&characterEncoding=UTF8&useSSL=false&serverTimezone=Asia/Shanghaiservlet:multipart:enabled: truemax-file-size: 10MBmax-request-size: 20MBaop:auto: truecross:origin: 'lrerp.com'audience:clientId: cbde72f64*****************00d3bbase64Secret: ZWExZjcxNzFi*********E2NGUwZTEzZjgxYmRkMzU=name: restapiuserexpiresSecond: 172800000
liteflow:print-banner: falserule-source-ext-data-map:driverClassName: com.mysql.cj.jdbc.Driverusername: 'lrerp'password: '******3'url: jdbc:mysql://pc-uf6fv9vxz81ws1y53.rwlb.rds.aliyuncs.com:3306/lingrong?useUnicode=yes&characterEncoding=UTF8&useSSL=false&serverTimezone=Asia/ShanghaiapplicationName: lingrongchainTableName: chainchainApplicationNameField: application_namechainNameField: chain_nameelDataField: el_dataalioss:url: file.lrerp.comendpoint: http://oss-cn-shanghai.aliyuncs.comaccessKeyId: LT#****************PPMacceddKeySecret: UVg***************C6LbucketName: lrerp
2. 微信小程序端
2.1 TDesign的upload组件
TDesign的upload组件 (tencent.com)https://tdesign.tencent.com/miniprogram/components/upload
1. app.json全局引用一下
2. wxml
如图可以看到mediaType中我只保留了模版中的image,bind:add事件我定义了一个handleCertificateAdd(),用于上传我的房屋产权图片,max修改为0,可以上传任意个图片
3. js
js页面主要修改了
1. data的数据:
定义一个数组 `certificateList:[ ]`就行
2. 【重点!】uploadFile()方法
token
这个token就是数据库中的token的值
3. handleCertificateAdd()方法
遍历上传的所有图片,通过调用上面的uploadFile方法
下面来分析这几个红框中的代码
1.
this.setData({certificateList: [...(this.data.certificateList), {...file,status: 'loading'}],});
2.
可以看到task的返回值参数res.progress为100
3.
[`certificateList[${length}].status`]: 'done'
就是把图片的status属性设置为done,图片显示出来不会一直转圈