Java實(shí)現(xiàn)文件分片上傳接口的示例代碼
java后端分片上傳接口
文件上傳工具--FileUtil
package com.youmejava.chun.util;
import lombok.Data;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 文件工具
*/
@Data
public class FileUtil {
private List<File> filelist;//文件列表
private String strPath;//路徑
public FileUtil() {
}
public FileUtil(List<File> filelist, String strPath) {
this.filelist = filelist;
this.strPath = strPath;
getFileList(this.strPath);
}
/**
* 獲取文件列表
* @param strPath
* @return
*/
public List<File> getFileList(String strPath) {
File dir = new File(strPath);
File[] files = dir.listFiles(); // 該文件目錄下文件全部放入數(shù)組
if (files != null) {
for (int i = 0; i < files.length; i++) {
String fileName = files[i].getName();
if (files[i].isDirectory()) { // 判斷是文件還是文件夾
getFileList(files[i].getAbsolutePath()); // 獲取文件絕對(duì)路徑
} else { // 判斷文件名
String strFileName = files[i].getAbsolutePath();
// System.out.println("---" + strFileName);
filelist.add(files[i]);
}
}
}
return filelist;
}
/**
* 合并文件
* @param from
* @param to
* @throws IOException
*/
public static void mergeFile(String from, String to) throws IOException {
File t = new File(to);
FileInputStream in = null;
FileChannel inChannel = null;
System.out.println("t "+t);
FileOutputStream out = new FileOutputStream(t,true);
FileChannel outChannel = out.getChannel();
File f = new File(from);
System.out.println("f "+f.isDirectory());
// 獲取目錄下的每一個(gè)文件名,再將每個(gè)文件一次寫(xiě)入目標(biāo)文件
if (f.isDirectory()) {
List<File> list = getAllFileAndSort(from);
System.out.println("sortlist "+list);
// 記錄新文件最后一個(gè)數(shù)據(jù)的位置
long start = 0;
for (File file : list) {
in = new FileInputStream(file);
inChannel = in.getChannel();
// 從inChannel中讀取file.length()長(zhǎng)度的數(shù)據(jù),寫(xiě)入outChannel的start處
outChannel.transferFrom(inChannel, start, file.length());
start += file.length();
in.close();
inChannel.close();
}
}
out.close();
outChannel.close();
}
/**
* 所有文件排序
* @param dirPath 文件根目錄路徑
* @return
*/
public static List<File> getAllFileAndSort(String dirPath) {
File dirFile = new File(dirPath);
File[] listFiles = dirFile.listFiles();
List<File> list = Arrays.asList(listFiles);
Collections.sort(list, (o1, o2) -> {
String _str=o1.getName().split("\\.")[0];
String _num=_str.split("_")[1];
String _str2=o2.getName().split("\\.")[0];
String _num2=_str2.split("_")[1];
return Integer.parseInt(_num) - Integer.parseInt(_num2);
});
return list;
}
/**
* 刪除文件夾
* 刪除文件夾需要把包含的文件及文件夾先刪除,才能成功
* https://blog.csdn.net/m0_57640408/article/details/120774050
* @param directory 文件夾名
* @return 刪除成功返回true,失敗返回false
*/
public static boolean deleteDirectory(String directory) {
// directory不以文件分隔符(/或\)結(jié)尾時(shí),自動(dòng)添加文件分隔符,不同系統(tǒng)下File.separator方法會(huì)自動(dòng)添加相應(yīng)的分隔符
if (!directory.endsWith(File.separator)) {
directory = directory + File.separator;
}
File directoryFile = new File(directory);
// 判斷directory對(duì)應(yīng)的文件是否存在,或者是否是一個(gè)文件夾
if (!directoryFile.exists() || !directoryFile.isDirectory()) {
System.out.println("文件夾刪除失敗,文件夾不存在" + directory);
return false;
}
boolean flag = true;
// 刪除文件夾下的所有文件和文件夾
File[] files = directoryFile.listFiles();
for (int i = 0; i < files.length; i++) { // 循環(huán)刪除所有的子文件及子文件夾
// 刪除子文件
if (files[i].isFile()) {
flag = deleteFile(files[i].getAbsolutePath());
if (!flag) {
break;
}
} else { // 刪除子文件夾
flag = deleteDirectory(files[i].getAbsolutePath());
if (!flag) {
break;
}
}
}
if (!flag) {
System.out.println("刪除失敗");
return false;
}
// 最后刪除當(dāng)前文件夾
if (directoryFile.delete()) {
System.out.println("刪除成功:" + directory);
return true;
} else {
System.out.println("刪除失敗:" + directory);
return false;
}
}
/**
* 刪除文件
*
* @param fileName 文件名
* @return 刪除成功返回true,失敗返回false
*/
public static boolean deleteFile(String fileName) {
File file = new File(fileName);
if (file.isFile() && file.exists()) {
file.delete();
System.out.println("刪除文件成功:" + fileName);
return true;
} else {
System.out.println("刪除文件失敗:" + fileName);
return false;
}
}
}分片上傳文件接口
?package com.youmejava.chun.commoninterface;
import com.youmejava.chun.util.FileUtil;
import com.youmejava.chun.util.ResultVo;
import com.youmejava.chun.util.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/apiSystem/upload")
@Api(value = "文件上傳", tags = "文件上傳")
public class UploadController {
@Value("${filePath1}")
private String filePath;
@PostMapping("/register")
@ApiOperation(value = "文件注冊(cè)", notes = "文件注冊(cè)")
@ApiImplicitParams({@ApiImplicitParam(value = "哈希值", name = "hash", required = true, paramType = "body")})
public ResultVo register(@RequestBody Map<String, Object> map) {
System.out.println("hash: " + map.get("hash"));
if (!StringUtil.isNotBlankAndNull(map.get("hash").toString())) {
// return ResultVo.failure("哈希值不可為空");
throw new ExpiredCredentialsException("哈希值不可為空!");
}
String _filePath=filePath;
if (!_filePath.endsWith("/")) {
_filePath+="/";
}
// String _pathStr = "C:\\Users\\JH-rent\\Desktop\\java啟動(dòng)文件\\test" + "\\" + map.get("hash");
String _pathStr=_filePath+map.get("hash");
//創(chuàng)建不同的文件夾目錄
File file = new File(_pathStr);
//判斷文件夾是否存在
if (!file.exists()) {
//如果文件夾不存在,則創(chuàng)建新的的文件夾
file.mkdirs();
}
File f = new File(_pathStr);
// 檢查目錄是否已上傳過(guò)文件,如果上傳過(guò),返回上傳個(gè)數(shù)
if (f.isDirectory()) {
File dirFile = new File(_pathStr);
File[] listFiles = dirFile.listFiles();
List<File> list = Arrays.asList(listFiles);
if (list == null&&list.size()>0) {
Map<String, Object>map1=new HashMap<>();
map1.put("number",list.size());
return ResultVo.success(map1);
}
}
return ResultVo.success();
}
@PostMapping("/uploadFile")
@ResponseBody
@ApiOperation(value = "上傳文件", notes = "上傳文件")
@ApiImplicitParams({@ApiImplicitParam(value = "哈希值", name = "hash", required = true, paramType = "body"), @ApiImplicitParam(value = "文件流", name = "file", required = true, paramType = "body"), @ApiImplicitParam(value = "文件名稱(chēng)", name = "fileName", required = true, paramType = "body"),})
public ResultVo uploadFile(HttpServletRequest request) {
MultipartHttpServletRequest params = ((MultipartHttpServletRequest) request);
List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");
String _fileName = params.getParameter("fileName");
String _hash = params.getParameter("hash");
if (!StringUtil.isNotBlankAndNull(_hash)) {
throw new ExpiredCredentialsException("哈希值不可為空!");
}
if (!StringUtil.isNotBlankAndNull(_fileName)) {
throw new ExpiredCredentialsException("文件名稱(chēng)不可為空!");
}
// System.out.println("_fileName: " + _fileName);
// System.out.println("_hash: " + _hash);
// System.out.println("files: " + files);
// System.out.println(params.getParameter("file"));
// String _pathStr = "C:\\Users\\JH-rent\\Desktop\\java啟動(dòng)文件\\test" + "\\" + _hash + "\\";
String _filePath=filePath;
if (!_filePath.endsWith("/")) {
_filePath+="/";
}
String _pathStr =_filePath+_hash+"/";
FileOutputStream fileOut = null;
//寫(xiě)入到文件(注意文件保存路徑的后面一定要加上文件的名稱(chēng))
try {
fileOut = new FileOutputStream(_pathStr + _fileName);
BufferedOutputStream bos = new BufferedOutputStream(fileOut);
BufferedInputStream bis = null;
for (MultipartFile file : files) {
// file.transferTo(new File(_pathStr + file.getOriginalFilename()));
// System.out.println(file.getInputStream());
bis = new BufferedInputStream(file.getInputStream());
}
byte[] buf = new byte[4096];
int length = bis.read(buf);
//保存文件
while (length != -1) {
bos.write(buf, 0, length);
length = bis.read(buf);
}
bos.close();
bis.close();
return ResultVo.success();
} catch (Exception e) {
e.printStackTrace();
return ResultVo.failure(e.getMessage());
}
}
@GetMapping("/getMergeFile")
@ApiOperation(value = "獲取合并文件", notes = "獲取合并文件")
@ApiImplicitParams({@ApiImplicitParam(value = "哈希值", name = "hash", required = true, dataType = "String"), @ApiImplicitParam(value = "文件名稱(chēng)", name = "fileName", required = true, dataType = "String")})
public ResultVo getMergeFile(@RequestParam(value = "hash") String hash, @RequestParam(value = "fileName") String fileName) {
// String _pathStr = "C:\\Users\\JH-rent\\Desktop\\java啟動(dòng)文件\\test" + "\\" + hash + "\\";
// String _pathStr1 = "C:\\Users\\JH-rent\\Desktop\\java啟動(dòng)文件\\test";
String _filePath=filePath;
if (!_filePath.endsWith("/")) {
_filePath+="/";
}
String _pathStr = _filePath + hash + "/";
String _pathStr1 = _filePath;
try {
// if (!_pathStr1.endsWith("\\")) {
// _pathStr1 += "\\";
// }
_pathStr1 += fileName;
FileUtil.mergeFile(_pathStr, _pathStr1);
//合并成功刪除加密文件
FileUtil.deleteDirectory(_pathStr);
} catch (IOException e) {
e.printStackTrace();
}
Map<String, Object>map=new HashMap<>();
map.put("fileUrl",_pathStr1);
return ResultVo.success(map);
}
}前端分片
單個(gè)文件下載或者分批壓縮多個(gè)文件下載
import JSZip from "jszip";
import fileSaver from "file-saver";
import axios from 'axios'
import {
Message,
Notification
} from "element-ui";
//下載單個(gè)文件
export const downloadSingleFile = (url, filename) => {
filename = filename || "文件名";
let suffix = /\.([0-9a-zA-Z]+)$/i.exec(url)[1];
const file_type = {
'doc': 'application/msword',
'bin': 'application/octet-stream',
'exe': 'application/octet-stream',
'so': 'application/octet-stream',
'dll': 'application/octet-stream',
'pdf': 'application/pdf',
'ai': 'application/postscript',
'xls': 'application/vnd.ms-excel',
'ppt': 'application/vnd.ms-powerpoint',
'dir': 'application/x-director',
'js': 'application/x-javascript',
'swf': 'application/x-shockwave-flash',
'xhtml': 'application/xhtml+xml',
'xht': 'application/xhtml+xml',
'zip': 'application/zip',
'mid': 'audio/midi',
'midi': 'audio/midi',
'mp3': 'audio/mpeg',
'rm': 'audio/x-pn-realaudio',
'rpm': 'audio/x-pn-realaudio-plugin',
'wav': 'audio/x-wav',
'bmp': 'image/bmp',
'gif': 'image/gif',
'jpeg': 'image/jpeg',
'jpg': 'image/jpeg',
'png': 'image/png',
'css': 'text/css',
'html': 'text/html',
'htm': 'text/html',
'txt': 'text/plain',
'xsl': 'text/xml',
'xml': 'text/xml',
'mpeg': 'video/mpeg',
'mpg': 'video/mpeg',
'avi': 'video/x-msvideo',
'movie': 'video/x-sgi-movie',
}
return new Promise((resolve, reject) => {
console.log(url, "url");
axios
.get(url, {
responseType: 'blob',
})
.then((res) => {
const blob = new Blob([res.data], {
type: file_type[suffix]
}) // 構(gòu)造一個(gè)blob對(duì)象來(lái)處理數(shù)據(jù),并設(shè)置文件類(lèi)型
if (window.navigator.msSaveOrOpenBlob) {
// 兼容IE10
navigator.msSaveBlob(blob, filename)
} else {
const href = URL.createObjectURL(blob) // 創(chuàng)建新的URL表示指定的blob對(duì)象
const a = document.createElement('a')
a.style.display = 'none'
a.href = href // 指定下載鏈接
a.download = filename // 指定下載文件名
a.click()
URL.revokeObjectURL(a.href) // 釋放URL對(duì)象
a.remove();
}
resolve("下載成功!")
})
})
}
let file_num = 0;
const zip = new JSZip();
let zip_obj = [];
let floder_obj = [];
let file_order = 0;
let file_floder = null;
let file_data = [];
let file_title = "";
let cur_title = "";
let breakpoint_num = 500; //斷點(diǎn)數(shù)據(jù)
let allowZipFile = true; //等待壓縮完成
/**
* [鏈接數(shù)組]
* @param {[type]} paths [{"name":"初三排課班級(jí)課表","path":""}]
* @return {[type]} 下載壓縮文件 [description]
*/
export const downloadCompressedFiles = ({
paths = [],
title = "文件批量下載",
percentCallback = () => {},
}) => {
allowZipFile = true;
file_order = 0;
cur_title = (title && title) || "文件批量下載";
file_title = paths.length > breakpoint_num ? title ? `${title}文件第1~${breakpoint_num}個(gè)` : `文件批量下載文件1~${breakpoint_num}個(gè)` : (title && title) || "文件批量下載";
zip_obj[file_order] = new JSZip();
floder_obj[file_order] = zip_obj[file_order].folder(file_title);
// file_floder = zip.folder((title && title) || "文件批量下載");
file_num = 0;
if (paths.length) {
file_data = paths;
if (file_num < paths.length) {
getUrlBlod(paths[file_num].path, paths[file_num].name, percentCallback);
}
}
}
const getUrlBlod = (url, name, percentCallback = () => {}) => {
// 從url獲取文件后綴
let suffix = /\.([0-9a-zA-Z]+)$/i.exec(url)[1];
let promise = httpPost({
url
}).then((data) => {
console.log(file_order, "data123");
// console.log(floder_obj[file_order]);
floder_obj[file_order].file(`${name}.${suffix}`, data, {
binary: true
}); //逐個(gè)添加文件
file_num = file_num + 1;
if (file_num != file_data.length) {
if (file_num % breakpoint_num == 0) {
let _temp = file_order;
file_order = file_order + 1;
// file_title = (breakpoint_num + file_num) <= file_data.length ? `${cur_title}文件第${breakpoint_num*_temp}~${file_num}個(gè)` : `${cur_title}文件第${file_num}~${file_data.length}個(gè)`;
file_title=`${cur_title}文件第${breakpoint_num*_temp}~${file_num}個(gè)`;
zip_obj[file_order] = new JSZip();
floder_obj[file_order] = zip_obj[file_order].folder((file_title && file_title) || "文件批量下載");
Notification({
title: '提示',
message: file_title + '開(kāi)始?jí)嚎s文件中!請(qǐng)等待',
type: 'info',
duration: 0
});
allowZipFile = false;
zipGenerateAsync(_temp, percentCallback);
}
percentCallback(file_num)
if (allowZipFile) {
getUrlBlod(file_data[file_num].path, file_data[file_num].name, percentCallback);
}
} else {
if (file_num >= file_data.length) {
file_title = `${cur_title}文件第${breakpoint_num * file_order}~${file_data.length}個(gè)`;
}
let _temp = file_order;
Notification({
title: '提示',
message: file_title + '開(kāi)始?jí)嚎s文件中!請(qǐng)等待',
type: 'info',
duration: 0
});
allowZipFile = false;
zipGenerateAsync(_temp, percentCallback);
}
return file_num;
}).catch(err => {
// console.log(err, "err123");
// Message.error(`${name}文件下載失敗!`);
file_num = file_num + 1;
if (file_num != file_data.length) {
if (file_num % breakpoint_num == 0) {
let _temp = file_order;
file_order = file_order + 1;
// file_title = (breakpoint_num + file_num) <= file_data.length ? `${cur_title}文件第${breakpoint_num*_temp}~${file_num}個(gè)` : `${cur_title}文件第${file_num}~${file_data.length}個(gè)`;
file_title=`${cur_title}文件第${breakpoint_num*_temp}~${file_num}個(gè)`;
zip_obj[file_order] = new JSZip();
floder_obj[file_order] = zip_obj[file_order].folder(file_title);
Notification({
title: '提示',
message: file_title + '開(kāi)始?jí)嚎s文件中!請(qǐng)等待',
type: 'info',
duration: 0
});
allowZipFile = false;
zipGenerateAsync(_temp, percentCallback);
}
percentCallback(file_num)
if (allowZipFile) {
getUrlBlod(file_data[file_num].path, file_data[file_num].name, percentCallback);
}
} else {
if (file_num >= file_data.length) {
file_title = `${cur_title}文件第${breakpoint_num * file_order}~${file_data.length}個(gè)`;
}
Notification({
title: '提示',
message: file_title + '開(kāi)始?jí)嚎s文件中!請(qǐng)等待',
type: 'info',
duration: 0
});
let _temp = file_order;
allowZipFile = false;
zipGenerateAsync(_temp, percentCallback);
}
});
}
const zipGenerateAsync = (num, percentCallback = () => {}) => {
zip_obj[num].generateAsync({
type: "blob"
}).then((content) => {
Notification({
title: '成功',
message: file_title + '壓縮文件下載成功',
type: 'success',
duration: 0
});
// 生成二進(jìn)制流
fileSaver.saveAs(
content,
(file_title && `${file_title}.zip`) || "文件批量下載.zip"
); // 利用file-saver保存文件
// Message.error(`壓縮文件下載成功!`);
if (file_num == file_data.length) {
file_num = file_num + 1;
}
percentCallback(file_num);
zip_obj[num] = "";
floder_obj[num] = "";
if (file_num < file_data.length) {
allowZipFile = true;
getUrlBlod(file_data[file_num].path, file_data[file_num].name, percentCallback);
}
// Message({
// message: '壓縮包文件下載成功!',
// type: 'success'
// });
}).catch(err => {
console.log(err, "壓縮下載失敗");
zip_obj[num] = "";
floder_obj[num] = "";
allowZipFile = true;
getUrlBlod(file_data[file_num].path, file_data[file_num].name, percentCallback);
Notification.error({
title: '錯(cuò)誤',
message: file_title + '壓縮下載失敗',
duration: 0
});
});
}
const getInPath = (url, name = "") => {
return new Promise(async (resolve, reject) => {
// let result = await axiosDownload(url);
// if (result) {
// resolve(result.data);
// } else {
// reject();
// }
await axiosDownload(url).then(res => {
resolve(res.data)
}).catch(err => {
reject(err)
})
});
};
const axiosDownload = (url, resOpts = {}) => {
const {
type = "get", data = ""
} = resOpts;
const queryArgs = {
url,
method: type,
data,
responseType: "blob",
// headers: {//這個(gè)地方看情況而定,如果打開(kāi)會(huì)存在跨域問(wèn)題
// Accept: "application/json",
// "Content-Type": "application/json; charset=utf-8",
// withCredentials: true,
// },
};
// tips: 這里直接返回的是response整體!
return new Promise((resolve, reject) =>
axios
.request(queryArgs)
.then((res) => resolve(res))
.catch((err) => reject(err))
);
};
const axiosConfig = {
// headers: {
// 'Content-Type': 'application/json;charset=UTF-8',
// },
// timeout: 60000,
responseType: 'blob',
}
const request = axios.create(axiosConfig);
let isRefreshing = false;
let queue = [];
let runQueue = () => {
isRefreshing = true
let first = queue.shift();
first.request()
}
//請(qǐng)求攔截
//所有的網(wǎng)絡(luò)請(qǐng)求都會(huì)先走這個(gè)方法
// 添加請(qǐng)求攔截器,所有的網(wǎng)絡(luò)請(qǐng)求都會(huì)先走這個(gè)方法,我們可以在它里面為請(qǐng)求添加一些自定義的內(nèi)容
request.interceptors.request.use((config) => {
// 在發(fā)送請(qǐng)求之前做些什么
return config;
}, function (error) {
return Promise.reject(error);
});
// 添加響應(yīng)攔截器
request.interceptors.response.use(function (response) {
isRefreshing = false
if (!(queue.length === 0)) runQueue()
return response.data
}, function (error) {
console.log(error, 2343);
isRefreshing = false
if (!(queue.length === 0)) runQueue()
// 對(duì)響應(yīng)錯(cuò)誤做點(diǎn)什么
return Promise.reject(error);
});
const httpPost = async ({
url,
method = 'get',
data = "",
}) => {
return new Promise((resolve, reject) => {
queue.push({
request: () => {
request({
method,
url,
data,
}).then(res => {
resolve(res)
}).catch(e => {
reject(e)
})
}
})
if (!isRefreshing) runQueue()
})
}以上就是Java實(shí)現(xiàn)文件分片上傳接口的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Java文件分片上傳的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)拖拽文件上傳dropzone.js的簡(jiǎn)單使用示例代碼
本篇文章主要介紹了Java實(shí)現(xiàn)拖拽文件上傳dropzone.js的簡(jiǎn)單使用示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07
使用@Autowired注解引入server服務(wù)層方法時(shí)報(bào)錯(cuò)的解決
這篇文章主要介紹了使用@Autowired注解引入server服務(wù)層方法時(shí)報(bào)錯(cuò)的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
springboot中報(bào)錯(cuò)Invalid character found in
這篇文章主要介紹了springboot中報(bào)錯(cuò)Invalid character found in the request的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
解決poi導(dǎo)出時(shí)單元格樣式被覆蓋問(wèn)題
這篇文章主要介紹了解決poi導(dǎo)出時(shí)單元格樣式被覆蓋問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Java定時(shí)器通信協(xié)議管理模塊Timer詳解
這篇文章主要介紹了Java定時(shí)器通信協(xié)議管理模塊Timer,?Timer一般指定時(shí)器(通信協(xié)議管理模塊)人類(lèi)最早使用的定時(shí)工具是沙漏或水漏,但在鐘表誕生發(fā)展成熟之后,人們開(kāi)始嘗試使用這種全新的計(jì)時(shí)工具來(lái)改進(jìn)定時(shí)器,達(dá)到準(zhǔn)確控制時(shí)間的目的2022-08-08
Mybatis實(shí)現(xiàn)傳入多個(gè)參數(shù)的四種方法詳細(xì)講解
這篇文章主要介紹了Mybatis實(shí)現(xiàn)傳入多個(gè)參數(shù)的四種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-01-01
Java處理異常2種機(jī)制關(guān)鍵字區(qū)別解析
這篇文章主要介紹了java處理異常2種機(jī)制關(guān)鍵字區(qū)別解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01
mybatisplus的坑?insert標(biāo)簽insert?into?select無(wú)參數(shù)問(wèn)題的解決
這篇文章主要介紹了mybatisplus的坑?insert標(biāo)簽insert?into?select無(wú)參數(shù)問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
詳解Spring Cloud 斷路器集群監(jiān)控(Turbine)
這篇文章主要介紹了詳解Spring Cloud 斷路器集群監(jiān)控(Turbine),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05

