通过动态分配地址来提升javaweb文件下载接口的其兼容性和可扩展性:
(上篇博文地址:https://blog.csdn.net/weixin_37766296/article/details/80044000)
log4j.properties 文件:
log4j.rootLogger = debug,stdout,D,Elog4j.logger.java.sql.ResultSet=INFOlog4j.logger.java.sql.apache=INFOlog4j.logger.java.sql.Connnection=DEGUGlog4j.logger.java.sql.Statement=DEGUGlog4j.logger.java.sql.PreparedStatement=DEGUGlog4j.appender.D = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.D.File = log4j.appender.D.Append = truelog4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayoutlog4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%nlog4j.appender.E = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.E.File = log4j.appender.E.Append = truelog4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayoutlog4j.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.propertiesprop.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 { // 如果是文件夹,则使用穷举的方法获取文件,写入ziptry {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日志文件输出为相对路径的解决方法)