Eap功能介绍 Jxls导出

 

导出jxls所涉及到的技能点

  • servlet规范
  • http协议的了解
  • view ViewResolver 接口理解
  • oop

为了应对复杂的excel导出,比如跨行,跨列,合并单元格等复杂操作.再使用poi操作,会很麻烦,现集成jxls进行导出操作.

使用

新建一个@RequestMappping方法,并指定exportFileName

@RequestMapping("1")
public ModelAndView test(){
    return new ModelAndView("jxls")
        .addObject("good",2)
        .addObject("title","一二三四")
        .addObject("exportFileName","测试");
}

jxls导出使用模板view接口进行处理,之前的导出配置表头,数据等已经在模板中定义了,但是导出的文件名因为字符编码的问题,最好通过addObject("exportFileName","测试");进行指定,如果不指定,取ModelAndView 的viewName 作为导出文件名(如果有路径,会进行处理) 比如上例的代码(没有最后一行exportFileNamekey的添加) 导出的文件名将会是 jxls.xls.

新建一个excel模板

  A B
1   ${title}
2 ${good} ${ss}

在A1单元格添加批注jx:area(lastCell="D3") 设置单元格模板范围

浏览器访问

浏览器访问http(s)://ip:port/.../1.sp.这样访问是会报错的,需要添加参数值export=jxls.

浏览器提示下载文件 文件名是测试.xls

导出的文件查看

  A B
1   一二三四
2 2  

这是模板替换以后生成的文件内容.因为在ModelAndView的model里没有提供变量ss,所以会在控制台报错,这种错误不影响文件的生成,但应该避免.

实现原理

view & ViewResolver

这两接口干嘛的请自行百度或者查看最后一个参考链接

eap 系统 所有的 ViewResolver

ViewResolver order 说明 SUFFIX !
EditorViewResolver 1 开发模式 .jsp.view ?dev
JxlsExcelViewResolver 5 jxls导出 .xls ?export=jxls
QInternalResourceViewResolver 10 默认的jsp .jsp  
QThymeleafViewResolver Integer.MAX_VALUE Thymeleaf html模板 .html  

这些解析器是需要配置成bean 在应用启动spring mvc会自动加载他们 持有其引用

JxlsExcelViewResolver & JxlsExcelView

开始扒源码


DispatcherServlet.doService(req,res);
进入doService()
 ↓
doDispatch(request, response);
进入doDispatch()
 ↓
servlet3.1支持的异步 可以极大的提升应用的并发 但不能提升响应速度
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 ↓
判断是否是文件上传请求
processedRequest = checkMultipart(request);
 ↓
确定 handler for the current request.  -->待扒
mappedHandler = getHandler(processedRequest);
 ↓
查找该请求所对应的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
 ↓
判断是否是get请求 并根据Last-Modified做出响应(缓存的一种最基本策略)
 ↓
执行拦截器链上定义的所有PreHandle
mappedHandler.applyPreHandle(processedRequest, response)
 ↓
执行经过aop字节码增强的@controller下的@RequestMapping方法(自己写的controller),返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
 ↓
如果返回的modelAndView没有viewName 根据提供的策略生成一个
applyDefaultViewName(processedRequest, mv);
 ↓
执行拦截器链上定义的所有PostHandle
mappedHandler.applyPostHandle(processedRequest, response, mv);
 ↓
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
进入processDispatchResult()
 ↓
根据返回的modelAndView对象,req,res 渲染出对应的响应写入res 
render(mv, request, response);
进入render()
 ↓
根据viewName 数据 国际化信息 确定到底用哪个view进行渲染
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
进入resolveViewName()
 ↓
根据上一小节的order排序 进行判断哪个视图解析器可以处理这个modelandview 如果可以处理返回一个view对象
for (ViewResolver viewResolver : this.viewResolvers) {
    View view = viewResolver.resolveViewName(viewName, locale);
    if (view != null) {
        return view;
    }
}
返回上一级
 ↓
调用render方法完成真正的数据渲染,将流 flush close
view.render(mv.getModelInternal(), request, response);
返回上一级
 ↓
执行拦截器链上定义的所有AfterCompletion
mappedHandler.triggerAfterCompletion(request, response, null);


JxlsExcelViewResolver

JxlsExcelViewResolver为了提高性能并不是直接实现的ViewResolver接口 而是继承的InternalResourceViewResolver,InternalResourceViewResolver继承了AbstractCachingViewResolver 提供了易用的缓存功能,提高了性能必须覆盖三个方法

@Override
protected View createView(String viewName, Locale locale) throws Exception {
    if (!canHandle(viewName, locale)) {
        return null;
    }
    return loadView(viewName, locale);
}

@Override
protected boolean canHandle(String viewName, Locale locale) {}

@Override
protected View loadView(String viewName, Locale locale) throws Exception {
    return new JxlsExcelView(viewName);
}

JxlsExcelView

JxlsExcelView继承了AbstractUrlBasedView 覆盖它的renderMergedOutputModel方法即可,也可以直接实现view接口实现render(),看自己了,想怎么搞怎么搞.

方法里面的逻辑就是根据viewName 找到模板 由jxls组件将数据渲染到 excel file 将file 写入response流中 flush and close

就是javase的东西了

参考链接

java使用jxls导出excel功能

Jxls+Spring MVC实现Excel导出

使用 jxls2.X 导出excel文件

jxls2.3-简明教程

SpringMVC视图机制详解[附带源码分析]