工作小结-持续更新
文件操作
页面上传文件到Controller
在后台系统中,上传文件功能非常常见,这是每个后台系统都应该实现的功能。在我们的魔方后台系统中。其中有个功能是需要导入卡号密码。实现方式如下:
上传文件
<input type="file" @change="importExcel" id="toImportExcel" style="display: none;"/>
调用方法,通过form表单的形式上传文件
importExcel: function (e) {
var file = e.target.files[0];
confirm('请确认导入模板类型?', function() {
var formData = new FormData();
$("#toImportExcel").val("");
formData.append('file', file);
formData.append('type', vm.type);
formData.append('productId', vm.product.productId);
$.ajax({
type: "POST",
async: false,
url: baseURL + "magic/product/import/excel",
data: formData,
cache: false,
contentType: false, //不可缺
processData: false, //不可缺
dataType: "json",
success: function (r) {
alert(r.msg);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("上传失败,请检查网络后重试");
}
});
})
},
通过MutipartFil接收传递过来的文件信息
@RequestMapping("import/excel")
public R importExcel(@RequestParam(value = "file",required = false)MultipartFile file,
@RequestParam(value = "type",required = false)Integer type,
@RequestParam(value = "productId",required = false)Long productId,
HttpServletRequest request){
... ...
}
在操作文件时包含了文件下载到本地、上传ftp、删除本地文件的过程。那么我们在下面具体分析下这几步
文件下载到本地
try {
//获取文件名称
String fileName = file.getOriginalFilename();
//校验文件名是csv格式
if (!fileName.matches("^.+\\.(?i)(csv)$")) {
String msg = "上传文件格式不正确,请输入csv格式!";
logger.error(msg);
return R.error(msg);
}
//获取扩展名
String ext = fileName.substring(fileName.lastIndexOf(".")+1);
//生成名称
String newFileName = UtilTools.getname();//自己写的一个获取字符串的方法作为图片名称
//生成放在服务器的路径
newFileName = newFileName + "." + ext;
//获取文件的上下文路径
String filePath = request.getServletContext().getRealPath("/WEB-INF/classes/upload/");
//创建一个文件
File newFile = new File(filePath + "/" + newFileName);
//将从前端上传的文件转移到这个新文件里
file.transferTo(newFile);
String paths = "/mofang/excel/" + DateUtil.getCurrentTime() + "/";
//文件上传到sftp
uploadSftp(newFileName,filePath,paths);
//调用activeMq
String msg = magicProductService.importSub(paths,"subpro_" + newFileName, type, productId);
//判断文件是否存在
if (newFile.exists()){
// 删除文件
if (newFile.delete()){
logger.info("删除本地文件:{}",newFile);
}
}
return R.ok(msg);
} catch (Exception e) {
logger.error("",e);
return R.error();
}
#UtilTools 这个写的真的辣鸡
public class UtilTools {
public static String getname(){
//年月日
//时分秒
Calendar now = Calendar.getInstance();
String str = "";
str += now.get(Calendar.YEAR);
if ((now.get(Calendar.MONTH) + 1)>=10){
str += (now.get(Calendar.MONTH) + 1);
}else {
str += "0" + (now.get(Calendar.MONTH) + 1);
}
if (now.get(Calendar.DAY_OF_MONTH)>=10){
str += now.get(Calendar.DAY_OF_MONTH);
}else {
str += "0" + now.get(Calendar.DAY_OF_MONTH);
}
if (now.get(Calendar.HOUR_OF_DAY)>=10){
str += now.get(Calendar.HOUR_OF_DAY);
}else {
str += "0" + now.get(Calendar.HOUR_OF_DAY);
}
if (now.get(Calendar.MINUTE)>=10){
str += now.get(Calendar.MINUTE);
}else {
str += "0" + now.get(Calendar.MINUTE);
}
if (now.get(Calendar.SECOND)>=10){
str += now.get(Calendar.SECOND);
}else {
str += "0" + now.get(Calendar.SECOND);
}
return str;
}
}
文件于sftp操作
sftp依赖
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
#SftpUtil.java
public class SftpUtil {
private static final String CLZ_NAME = SftpUtil.class.getSimpleName() + ".";
static Logger logger= LoggerFactory.getLogger(SftpUtil.class);
private ChannelSftp sftp;
private Session session;
/**
* SFTP 登录用户名
*/
private String username;
/**
* SFTP 登录密码
*/
private String password;
/**
* 私钥
*/
private String privateKey;
/**
* SFTP 服务器地址IP地址
*/
private String host;
/**
* SFTP 端口
*/
private int port;
/**
* 构造基于密码认证的sftp对象
*/
public SftpUtil(String username, String password, String host, int port) {
this.username = username;
this.password = password;
this.host = host;
this.port = port;
}
/**
* 构造基于秘钥认证的sftp对象
*/
public SftpUtil(String username, String host, int port, String privateKey) {
this.username = username;
this.host = host;
this.port = port;
this.privateKey = privateKey;
}
public SftpUtil() {
}
/**
* 连接sftp服务器
*/
public void login() throws Exception {
JSch jsch = new JSch();
if (privateKey != null) {
jsch.addIdentity(privateKey);// 设置私钥
}
session = jsch.getSession(username, host, port);
if (password != null) {
session.setPassword(password);
}
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
//TODO 移除kerberos验证方法
config.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
session.setConfig(config);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
}
/**
* 关闭连接 server
*/
public void logout() {
if (sftp != null) {
if (sftp.isConnected()) {
sftp.disconnect();
}
}
if (session != null) {
if (session.isConnected()) {
session.disconnect();
}
}
}
/**
* 将输入流的数据上传到sftp作为文件。文件完整路径=basePath+directory
*
* @param path 上传到该目录
* @param fileName sftp端文件名
* @param input 输入流
*/
public void upload(String path, String fileName, InputStream input) throws SftpException {
try {
sftp.cd(path);
} catch (SftpException e) {
//目录不存在,则创建文件夹
String[] dirs = path.split("/");
for (String dir : dirs) {
if (null == dir || "".equals(dir)) continue;
try {
sftp.cd(dir);
} catch (SftpException ex) {
sftp.mkdir(dir);
sftp.cd(dir);
}
}
}
sftp.put(input, fileName); //上传文件
}
/**
* 下载文件。
*
* @param directory 下载目录
* @param downloadFile 下载的文件
* @param saveFile 存在本地的路径
*/
public void download(String directory, String downloadFile, String saveFile) throws SftpException, FileNotFoundException {
if (directory != null && !"".equals(directory)) {
sftp.cd(directory);
}
File file = new File(saveFile);
sftp.get(downloadFile, new FileOutputStream(file));
}
/**
* 删除文件
*
* @param directory 要删除文件所在目录
* @param deleteFile 要删除的文件
*/
public void delete(String directory, String deleteFile) throws SftpException {
sftp.cd(directory);
sftp.rm(deleteFile);
}
/**
* 列出目录下的文件
*
* @param directory 要列出的目录
* @param
*/
public Vector<?> listFiles(String directory) throws SftpException {
return sftp.ls(directory);
}
}
上传文件到sftp
public void uploadSftp(String newFileName,String filePath,String paths){
// 创建sftp连接
SftpUtil sftp = new SftpUtil(sUsername, sPassword, sHost, Integer.parseInt(sPort));
// 输入流
InputStream is = null;
try {
// 获取文件输入流
is = new FileInputStream(filePath + newFileName);
// sftp登录
sftp.login();
// sftp下载文件
sftp.upload(paths, "subpro_" + newFileName, is);
} catch (Exception e) {
logger.error("",e);
} finally {
if (is != null){
try {
is.close();
sftp.logout();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
sftp下载文件到本地
public void sftpTestDownload() {
logger.info("begin");
// 测试上传
try {
// 创建sftp连接
SftpUtil sftp = new SftpUtil(sUsername, sPassword, sHost, Integer.parseInt(sPort));
// 登录
sftp.login();
String pathName="/mofang/excel/20190701/";
String fileName="subpro_1561967527887.csv";
// 下载
sftp.download(pathName, fileName, "D:\\test\\"+fileName);
// 登出
sftp.logout();
logger.info("ends");
} catch (Exception e) {
logger.error("", e);
}
}
获取上下文路径
通过request获取
HttpServletRequest request
request.getServletContext().getRealPath("/WEB-INF/classes/upload/");
springboot获取上下文路径
ResourceUtils.getURL("classpath:").getPath()
spring-core ResourceUtils 常用url
public static final String CLASSPATH_URL_PREFIX = "classpath:";
public static final String FILE_URL_PREFIX = "file:";
public static final String JAR_URL_PREFIX = "jar:";
public static final String WAR_URL_PREFIX = "war:";
public static final String URL_PROTOCOL_FILE = "file";
public static final String URL_PROTOCOL_JAR = "jar";
public static final String URL_PROTOCOL_WAR = "war";
public static final String URL_PROTOCOL_ZIP = "zip";
public static final String URL_PROTOCOL_WSJAR = "wsjar";
public static final String URL_PROTOCOL_VFSZIP = "vfszip";
public static final String URL_PROTOCOL_VFSFILE = "vfsfile";
public static final String URL_PROTOCOL_VFS = "vfs";
public static final String JAR_FILE_EXTENSION = ".jar";
public static final String JAR_URL_SEPARATOR = "!/";
public static final String WAR_URL_SEPARATOR = "*/";
Shiro出现的问题
用户用chrom登录shiro抛出异常
这个其实就是记住我的功能,因为第一次登录没有任何信息,所以就会抛出异常。将这个功能置为null就可以
2019-07-11 20:29:22.288 WARN 314244 --- [nio-8088-exec-6] o.a.shiro.mgt.AbstractRememberMeManager : There was a failure while trying to retrieve remembered principals. This could be due to a configuration problem or corrupted principals. This could also be due to a recently changed encryption key, if you are using a shiro.ini file, this property would be 'securityManager.rememberMeManager.cipherKey' see: http://shiro.apache.org/web.html#Web-RememberMeServices. The remembered identity will be forgotten and not used for this request.
2019-07-11 20:29:22.290 WARN 314244 --- [nio-8088-exec-6] o.a.shiro.mgt.DefaultSecurityManager : Delegate RememberMeManager instance of type [org.apache.shiro.web.mgt.CookieRememberMeManager] threw an exception during getRememberedPrincipals().
org.apache.shiro.crypto.CryptoException: Unable to execute 'doFinal' with cipher instance [javax.crypto.Cipher@3b8690dc].
at org.apache.shiro.crypto.JcaCipherService.crypt(JcaCipherService.java:462)
at org.apache.shiro.crypto.JcaCipherService.crypt(JcaCipherService.java:445)
at org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:390)
at org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:382)
at org.apache.shiro.mgt.AbstractRememberMeManager.decrypt(AbstractRememberMeManager.java:482)
at org.apache.shiro.mgt.AbstractRememberMeManager.convertBytesToPrincipals(AbstractRememberMeManager.java:419)
at org.apache.shiro.mgt.AbstractRememberMeManager.getRememberedPrincipals(AbstractRememberMeManager.java:386)
at org.apache.shiro.mgt.DefaultSecurityManager.getRememberedIdentity(DefaultSecurityManager.java:612)
at org.apache.shiro.mgt.DefaultSecurityManager.resolvePrincipals(DefaultSecurityManager.java:500)
at org.apache.shiro.mgt.DefaultSecurityManager.createSubject(DefaultSecurityManager.java:346)
at org.apache.shiro.subject.Subject$Builder.buildSubject(Subject.java:845)
at org.apache.shiro.web.subject.WebSubject$Builder.buildWebSubject(WebSubject.java:148)
at org.apache.shiro.web.servlet.AbstractShiroFilter.createSubject(AbstractShiroFilter.java:292)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:359)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:130)
at org.springframework.boot.web.servlet.support.ErrorPageFilter.access$000(ErrorPageFilter.java:66)
at org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:105)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:123)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:991)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at org.apache.shiro.crypto.JcaCipherService.crypt(JcaCipherService.java:459)
... 57 common frames omitted
- 解决方法
将rememberMeManager置为null,就不报异常信息了。
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRememberMeManager(null);
maven的profile切换环境的参数
下图是项目的文件结构
<profiles>
<profile>
<id>dev</id>
<properties>
<profileActive>dev</profileActive>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>uat</id>
<properties>
<profileActive>uat</profileActive>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<profileActive>prod</profileActive>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<profileActive>test</profileActive>
</properties>
</profile>
</profiles>
activeByDefault标签的值为true,表示默认的profile,使用mvn install就会打成dev的包
resources标签定义要包含的资源,在下面的配置下package阶段会把resouces文件里的 $application-${profileActive}.properties 文件打包
这里的${profileActive}由命令maven的-P选项指定,例:mvn install -Ptest 就是打包
即application-${profileActive}.properties、application.properties、**/*.xml文件
<build>
<resources>
<resource>
<directory>src/main/webapp</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>application-${profileActive}.properties</include>
<include>application.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
#application.properties
server.port=10027
#profileActive就是上面resource中的profileActive
spring.profiles.active=@profileActive@
JSONArray数据转换成Java List
后台接收json数组转成封装实体类的List
import java.util.List;
import net.sf.json.JSONArray;
import net.sf.json.JsonConfig;
public class JsonTest {
/**
* @param args
*/
public static void main(String[] args) {
// 转换方法1
JSONArray array = JSONArray.fromObject("[{'name':'hehe','age':22}]");
List<Person> list = JSONArray.toList(array, Person.class);// 过时方法
System.out.println(list.get(0).getName());
// 转换方法2
List<?> list2 = JSONArray.toList(array, new Person(), new JsonConfig());//参数1为要转换的JSONArray数据,参数2为要转换的目标数据,即List盛装的数据
Person person = (Person) list2.get(0);
System.out.println(person.getAge());
}
}