除了常見的jsp視圖外,還有pdf,excel等。不管哪種視圖,都會實現(xiàn)SpringMvc定義的視圖接口View。這篇文章就講講怎么使用Pdf視圖----AbstractPdfView。
AbstractPdfView屬于非邏輯視圖,不需要任何的視圖解析器(ViewResolver)去定位。它是一個抽象類,有一個抽象方法需要我們?nèi)崿F(xiàn)。
/**
* 通過數(shù)據(jù)模型自定義創(chuàng)建pdf文檔
* @param model 數(shù)據(jù)模型
* @param document 代表一個pdf文檔
* @param writer pdf寫入器
* @param request HttpServletRequest請求對象
* @param response HttpServletResponse響應(yīng)對象
*/
protected abstract void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer,
HttpServletRequest request, HttpServletResponse response) throws Exception;
我們首先創(chuàng)建一個Spring Boot工程,這里的orm使用Mybatis,數(shù)據(jù)源使用Druid,為了能夠使用pdf,我們需要加pom.xml中相關(guān)的依賴,下面貼出完整的pom文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- pdf相關(guān)的jar -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>core-renderer</artifactId>
<version>R8</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.12</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
</dependencies>
繼承了AbstractPdfView后,就得實現(xiàn)它的抽象方法,從而完成導(dǎo)出的邏輯,而每個控制器可能都有不同的導(dǎo)出邏輯,所以為了適應(yīng)不同控制器的自定義導(dǎo)出,先定義一個導(dǎo)出接口。
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lowagie.text.Document;
import com.lowagie.text.pdf.PdfWriter;
/**
* 定義一個導(dǎo)出的接口,方便每個控制器實現(xiàn)自己的導(dǎo)出邏輯
* @author liu
*/
public interface PdfExportService {
/**
* 導(dǎo)出的方法
* @param model 數(shù)據(jù)模型
* @param document 代表一個pdf文檔
* @param writer pdf寫入器
* @param request HttpServletRequest請求對象
* @param response HttpServletResponse響應(yīng)對象
*/
public void make(Map<String, Object> model, Document document, PdfWriter writer,
HttpServletRequest request, HttpServletResponse response);
}
注意這里導(dǎo)的是com.lowagie.text包下的類。
有了這個接口后,各個控制器只需要實現(xiàn)這個接口,就能自定義導(dǎo)出pdf的邏輯。
接著就是繼承AbstractPdfView,通過它調(diào)度PdfExportService 的make方法就可以讓控制器去實現(xiàn)自定義的導(dǎo)出邏輯。
/**
* 繼承AbstractPdfView類,實現(xiàn)抽象方法buildPdfDocument
* @author liu
*/
public class PdfView extends AbstractPdfView {
private PdfExportService pdfExportService = null;
/**
* 創(chuàng)建對象時載入導(dǎo)出服務(wù)接口
* @param pdfExportService
*/
public PdfView(PdfExportService pdfExportService) {
this.pdfExportService = pdfExportService;
}
/**
* 調(diào)用接口實現(xiàn)導(dǎo)出
*/
@Override
protected void buildPdfDocument(Map<String, Object> model, Document document, PdfWriter writer,
HttpServletRequest request, HttpServletResponse response) throws Exception {
// 調(diào)用導(dǎo)出服務(wù)接口類
pdfExportService.make(model, document, writer, request, response);
}
}
這里可以看到,在創(chuàng)建自定義pdf視圖時,需要自定義一個導(dǎo)出服務(wù)接口(PdfExportService ),通過實現(xiàn)這個接口,每個控制器都可以自定義其導(dǎo)出的邏輯。
完成了上面的工作,接下來就是正常的SSM結(jié)合。首先在Spring Boot的配置文件中進行配置
# 數(shù)據(jù)庫配置
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/springboot?characterEncoding=utf-8
jdbc.username = root
jdbc.password = 1311664842
# mybatis 配置文件的路徑
mybatis_config_file = /mybatis/mybatis-config.xml
# 映射文件的路徑
mapper_path = /mapper/**.xml
# 實體類的路徑
entity_package = com.codeliu.entity
# 日志配置
logging.level.root = DEBUG
logging.level.org.springframework = DDEBUG
logging.level.org.mybatis = DEBUG
可以看到進行了數(shù)據(jù)源的配置,還有mybatis的一些配置。
接下來就是在指定路徑下創(chuàng)建mybatis全局配置文件,創(chuàng)建實體類和創(chuàng)建映射文件,還有service層,這些就不寫了,最重要的就是控制層,在寫控制層之前,先寫兩個配置類,配置數(shù)據(jù)源和sqlSessionFactory。
/**
* 配置數(shù)據(jù)源
* @author liu
*/
@Configuration
// 掃描dao層
@MapperScan(value = "com.codeliu.dao")
public class DataSourceConfig {
@Value(value = "${jdbc.driver}")
private String jdbcDriver;
@Value(value = "${jdbc.url}")
private String jdbcUrl;
@Value(value = "${jdbc.username}")
private String jdbcUsername;
@Value(value = "${jdbc.password}")
private String jdbcPassword;
@Bean(value = "dataSource")
public DruidDataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(jdbcDriver);
dataSource.setUrl(jdbcUrl);
dataSource.setUsername(jdbcUsername);
dataSource.setPassword(jdbcPassword);
return dataSource;
}
}
/**
* SqlSessionFactory配置
* @author liu
*/
@Configuration
public class SqlSessionFactoryConfig {
// mybatis配置文件的路徑
@Value(value = "${mybatis_config_file}")
private String mybatisConfigPath;
// mybatis映射文件的路徑
@Value(value = "${mapper_path}")
private String mapperPath;
// 實體包的路徑
@Value(value = "${entity_package}")
private String entityPath;
@Autowired
private DataSource dataSource;
@Bean(value = "sqlSessionFactory")
public SqlSessionFactoryBean getSqlSessionFactoryBean() throws IOException {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
// mybatis配置文件的路徑
sqlSessionFactory.setConfigLocation(new ClassPathResource(mybatisConfigPath));
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
String packageSearchPath = PathMatchingResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + mapperPath;
// 指定映射文件的路徑
sqlSessionFactory.setMapperLocations(resolver.getResources(packageSearchPath));
// 配置數(shù)據(jù)源
sqlSessionFactory.setDataSource(dataSource);
// 配置實體包的掃描路徑
sqlSessionFactory.setTypeAliasesPackage(entityPath);
return sqlSessionFactory;
}
}
注意加上了@Configuration注解,表示這是一個配置類。這樣Spring Boot啟動的時候,就會進行相關(guān)的初始化。
現(xiàn)在可以來進行controller的編寫。
@Controller
@RequestMapping("/man")
public class ManController {
@Autowired
private ManService manService;
/**
* 導(dǎo)出接口
* @return
*/
@GetMapping("/export/pdf")
public ModelAndView exportPdf() {
List<Man> manList = manService.getManList();
// 定義pdf視圖
View view = new PdfView(exportService());
ModelAndView mv = new ModelAndView();
// 設(shè)置視圖
mv.setView(view);
// 加入數(shù)據(jù)模型
mv.addObject("manList", manList);
return mv;
}
/**
* 導(dǎo)出pdf自定義,每個控制器可以實現(xiàn)自己的導(dǎo)出邏輯
* @return
*/
@SuppressWarnings("unchecked")
public PdfExportService exportService() {
// 使用Lambda表達式
return(model, document, writer, request, response)-> {
try {
// A4紙張
document.setPageSize(PageSize.A4);
// 標題
document.addTitle("用戶信息");
// 換行
document.add(new Chunk("\n"));
// 表格,3列
PdfPTable table = new PdfPTable(3);
// 單元格
PdfPCell cell = null;
// 字體,定義為藍色加粗
Font f8 = new Font();
f8.setColor(Color.BLUE);
f8.setStyle(Font.BOLD);
// 標題
cell = new PdfPCell(new Paragraph("id", f8));
// 居中對齊
cell.setHorizontalAlignment(1);
// 將單元格加入表格
table.addCell(cell);
// 標題
cell = new PdfPCell(new Paragraph("age", f8));
// 居中對齊
cell.setHorizontalAlignment(1);
// 將單元格加入表格
table.addCell(cell);
// 標題
cell = new PdfPCell(new Paragraph("name", f8));
// 居中對齊
cell.setHorizontalAlignment(1);
// 將單元格加入表格
table.addCell(cell);
// 獲取數(shù)據(jù)模型中的manList
List<Man> manList = (List<Man>)model.get("manList");
for(Man man:manList) {
document.add(new Chunk("\n"));
cell = new PdfPCell(new Paragraph(man.getId() + ""));
// 居中對齊
cell.setHorizontalAlignment(1);
table.addCell(cell);
cell = new PdfPCell(new Paragraph(man.getAge() + ""));
// 居中對齊
cell.setHorizontalAlignment(1);
table.addCell(cell);
cell = new PdfPCell(new Paragraph(man.getName()));
// 居中對齊
cell.setHorizontalAlignment(1);
table.addCell(cell);
}
// 文檔中加入表格
document.add(table);
} catch(DocumentException e) {
e.printStackTrace();
}
};
}
}
可以看到我們先通過數(shù)據(jù)庫查詢出數(shù)據(jù),然后放入模型和視圖(ModelAndView)中,然后設(shè)置pdf視圖(PdfView)。而定義PdfView時,使用Lambda表達式實現(xiàn)了導(dǎo)出服務(wù)接口,這樣就可以很方便的讓每一個控制器自定義樣式和數(shù)據(jù)。導(dǎo)出pdf文件的邏輯在exportService方法中。
啟動Spring Boot文件后,輸入url,顯示下面的結(jié)果
