通过动态分配地址来提升javaweb文件下载接口的其兼容性和可扩展性:
(上篇博文地址:https://blog.csdn.net/weixin_37766296/article/details/80044000)
log4j.properties 文件:
log4j.rootLogger = debug,stdout,D,E
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.java.sql.apache=INFO
log4j.logger.java.sql.Connnection=DEGUG
log4j.logger.java.sql.Statement=DEGUG
log4j.logger.java.sql.PreparedStatement=DEGUG
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File =
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
你会发现:
log4j.appender.D.File =
这里是空的,不急,容我慢慢解释。
上面是日志文件的配置。下面是web.xml文件的配置:
<!-- log4j文件的配置 (千万要注意的是下面的classes记得加上去,虽然工程目录可能没有,但是实际目录可能是有的)-->
<servlet>
<servlet-name>lo4jInit</servlet-name> ()
<servlet-class>com.fx.init.Lo4jInit</servlet-class> (这里要慎重,servlet类名:由package+class名组成)
<init-param>
<param-name>log4j_init_path</param-name> (这里是用来初始化的一些参数,在init()方法中通过getInitParameter()方法获得)
<param-value>WEB-INF\classes\log4j.properties</param-value> (跟上面一个参数匹配,类似于一对键值对)
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
web容器启动时是先 初始化web.xml文件,然后在根据web.xml中的配置进行部署
接下来就是init()方法的实现了。。
public class Lo4jInit extends HttpServlet {
private static final long serialVersionUID = 1L;
private static Logger logger = Logger.getLogger(Lo4jInit.class);
/* web容器初始化 */
public void init() {
/* 部署在tomcat下的绝对路径 */
String path = this.getServletContext().getRealPath("/");
/* 获取web.xml文件中name为log4j_init_path的value值 */
String file = this.getInitParameter("log4j_init_path");
if (file != null) {
Properties prop = new Properties();
String root = path;
/* 设置文件输出的路径 */
String root1 = root + "/logs/log.txt";
String root2 = root + "logs/error.txt";
System.out.println("root1:" + root1);
System.out.println("root2:" + root2);
try {
prop.load(new FileInputStream(path + file)); // 加载log4j.properties
prop.setProperty("log4j.appender.D.File", root1); // 设置日志文件的输出路径
prop.setProperty("log4j.appender.E.File", root2); // 设置日志文件的输出路径
PropertyConfigurator.configure(prop); // 加载配置项
} catch (Exception e) {
System.out.println("any exception??");
logger.info("初始化log4j日志输入路径异常,请检查web.xml参数配置是否正常,异常发生在" + this.getClass().getName()
+ "类的public void init()方法,异常的愿意是:" + e.getMessage(), e.fillInStackTrace());
}
}
}
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}
最后附上download接口的实现:(在之前一篇博文我有详细介绍,这里就不详细介绍了)
@Controller
public class FilesController {
@RequestMapping(value = "/download")
public void download(HttpServletRequest request, HttpServletResponse response) throws Exception {
String zipBasePath = request.getSession().getServletContext().getRealPath("/logs");
System.out.println("starting download...");
/* 判断文件夹是否有文件,遍历文件夹中的文件。。。 */
String path = zipBasePath;
Vector<String> vecFile = new Vector<String>();
recursion(path, vecFile);
System.out.println("文件路径分别是:");
for (String fileName : vecFile) {
System.out.println(fileName);
}
/* 设置下载文件的名称 */
String fileName = "logs.zip";
response.setContentType("text/html; charset=UTF-8"); // 设置编码字符
response.setContentType("application/x-msdownload"); // 设置内容类型为下载类型
response.setHeader("Content-disposition", "attachment;filename=" + fileName);// 设置下载的文件名称
OutputStream out = response.getOutputStream(); // 创建页返回方式为输出流,会自动弹出下载框
/* 创建压缩文件需要的空的zip包 ,这里是自动生成的,不用我们自己去生成 */
String zipFilePath = zipBasePath + "temp.zip";
System.out.println("create the empty zip file successfully...");
/* 根据临时的zip压缩包路径,创建zip文件 */
File zip = new File(zipFilePath);
if (!zip.exists()) {
zip.createNewFile();
}
System.out.println("create the zip file successfully...");
/* 创建zip文件输出流 */
FileOutputStream fos = new FileOutputStream(zip);
ZipOutputStream zos = new ZipOutputStream(fos);
System.out.println("create the empty zip stream successfully....");
/* 循环读取文件路径集合,获取每一个文件的路径(将文件一个一个进行压缩) */
for (String fp : vecFile) {
File f = new File(fp); // 根据文件路径创建文件
zipFile(f, zos); // 将每一个文件写入zip文件包内,即进行打包
}
zos.close();
System.out.println("files zipped over, starting to download");
/* 将打包后的文件写到客户端,有两种方法可以实现(下面会进行介绍),这里使用缓冲流输出 */
InputStream fis = new BufferedInputStream(new FileInputStream(zipFilePath));
byte[] buff = new byte[4096];
int size = 0;
while ((size = fis.read(buff)) != -1) {
out.write(buff, 0, size);
}
System.out.println("package is download successfully");
// 释放和关闭输入输出流
out.flush();
out.close();
fis.close();
}
public void zipFile(File inputFile, ZipOutputStream zipoutputStream) {
try {
if (inputFile.exists()) { // 判断文件是否存在
if (inputFile.isFile()) { // 判断是否属于文件,还是文件夹
// 创建输入流读取文件
FileInputStream fis = new FileInputStream(inputFile);
BufferedInputStream bis = new BufferedInputStream(fis);
// 将文件写入zip内,即将文件进行打包
ZipEntry ze = new ZipEntry(inputFile.getName()); // 获取文件名
zipoutputStream.putNextEntry(ze);
// 写入文件的方法,同上
byte[] b = new byte[1024];
long l = 0;
while (l < inputFile.length()) {
int j = bis.read(b, 0, 1024);
l += j;
zipoutputStream.write(b, 0, j);
}
// 关闭输入输出流
bis.close();
fis.close();
} else { // 如果是文件夹,则使用穷举的方法获取文件,写入zip
try {
File[] files = inputFile.listFiles();
for (int i = 0; i < files.length; i++) {
zipFile(files[i], zipoutputStream);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void recursion(String root, Vector<String> vecFile) {
String path = root;
File file = new File(root);
if (file.exists()) {
System.out.println("this file is exit!");
File[] subFile = file.listFiles();
for (int i = 0; i < subFile.length; i++) {
if (subFile[i].isDirectory()) {
recursion(subFile[i].getAbsolutePath(), vecFile);
} else {
String filename = subFile[i].getName();
vecFile.add(path + File.separator + filename);
}
}
} else {
System.out.println("this file is not exit!");
}
}
}
最后总结一下编程过程中遇到一些困难以及解决方法:
1. 在编写Spring的applicationContext.xml文件时,无缘无故出现了:
cvc-complex-type.2.3: Element 'beans' cannot have character [children], because the type's content type is element-only.错误。
错误原因:Spring在初始化的时候无法识别applicationContext.xml中的元素。
可能产生该错误的原因:网上复制的代码直接粘贴到了xml文件中,而网上的代码可能不符合xml规范
解决办法:1.去掉xml文件中的中文注解,因为复制的有些注解Spring不能识别。
2.若仍然有错,则尝试修改多余的空格,因为中文空格Spring有可能识别错误。
3.最后的绝招:重新手动抄写一遍文件内容,保存。
参考博文:https://blog.csdn.net/mafan121/article/details/43266733
2. 在配置web.xml 文件中对配置的元素不是很熟悉:
可以看到,在配置Servlet时,有两个地方需要配置,一个是<servlet>,另一个是<servlet-Mapping>,这两个一个是配置Servlet,一个是配置其映射信息,其中<servlet>中的<servlet-name>可以随意指定,但要有一定的意义,一般取为类的名称,例如我的类名为ServletDemo,这里取名为ServletDemo,下面的<servlet-class>是类的全路径,package+classname,一定要是全路径!
<servlet-Mapping>是映射信息,它也有一个<servlet-name>,里面的名字是对应的Servlet名,也就是我们上面配置的Servlet名字,这里是ServletDemo,下面的是映射路径,也就是访问Servlet的名称,这里也是以方便和有意义为前提的,是我们在访问Servlet在浏览器地址栏后面输入的那个信息,例如我的映射路径命名为/servlet,在地址栏中输入http://localhost:8080/servlet
注意:这里的映射路径一定不能丢掉/,否则就会出错了,一定要写成/servlet,不能是servlet。
参考博文:https://blog.csdn.net/m0_37630602/article/details/65443660
3.
eclipse项目一直显示有错,但是一直找不到错误在哪里
这天在写项目的时候碰到了这么个问题,项目上一直提示着红叉,但不管是文件里还是java buildpath里都找不到报错,然后我就郁闷了。
后来给我找到一个解决方案,能查看当前错误是什么:
eclipse–>Window–>show View–>Markers,出现一个面板,然后在这个面板里就能查看到底是什么在出错啦。
参考博文:https://blog.csdn.net/zhagzheguo/article/details/51660908
4.
参考博文:http://lpcjrflsa.iteye.com/blog/1101796(Log4j日志文件输出为相对路径的解决方法)