一、概述
观前提示:集成步骤在第三小节(并非完整版,需自行修改)
springMVC项目集成打印插件(对springBoot应该也适用,因为并不涉及框架,只需正确返回数据用于展示即可),旧项目用的是iReprort插件,新项目是采用新的框架,新框架因为没有集成打印插件,所以需要选择打印插件,在V2EX上看到,常用的打印插件有lodop,httpPrinter。
二、插件对比
- lodop
优点:打印功能齐全,调用简单,JS直接调用,内容也是在js设置(水平问题,只在js设置过,如果有别的方式,当我没说过)
缺点:收费(且有众多版本,各个版本的收费还不一样,因为公司项目只有小项目,收费的基本不考虑),免费版本和破解版本是打印会有水印 - HttpPrinter
优点:仅源码收费,使用无限制,打印无水印;打印功能齐全,调用简单;可以自己建模板,有完整的模板管理;集成了一些其他的功能,比如身份证信息读取、base64文件转码解码等
缺点:模板功能不是十分齐全(貌似不能插入2张以上列表,也是由于这个原因,最后停止了继续集成,所以第三节的代码并不是即取即用,有些地方是直接写死的,需要自己写活)
三、集成
- 插件下载
自行下载后解压即可:https://httpprinter.lanzous.com/b0z4x6wf(我用的是2.0.0.11版本) - 运行插件
- 模板制作
在图中的文件夹下新建一个grf模板文件来制作模板,该目录下有已经准备好的demo,可以根据需要进行参考。
4.代码集成
代码中各层所继承或实现的类或接口都是所使用框架集成的,如果你的框架没有这些东西,可以删除这部分代码
Controller层:
@Controller
@RequestMapping(value = "${adminPath}/sys/user")
public class UserController extends BaseController {
@Autowired
private SystemService systemService;
@ResponseBody
@RequestMapping("testPrint")
public List<User> getAllUser() {
List<User> allUser = systemService.getAllUser();
return allUser;
}
}
Service层:
@Service
@Transactional(readOnly = true)
public class SystemService extends BaseService implements InitializingBean {
@Autowired
private UserDao userDao;
public List<User> getAllUser() {
return userDao.getAllUser();
}
}
Dao层:
@MyBatisDao
public interface UserDao extends CrudDao<User> {
/**
* 查询所有用户
* @return
*/
public List<User> getAllUser();
}
Mapper:
<select id="getAllUser" resultType="User">
select
a.name,
a.mobile,
a.login_name,
a.email,
a.no,
a.del_flag
from sys_user a
</select>
页面:
<script type="text/javascript">
$(function () {
$("#btnPrint").click(function () {
$.ajax({
url: "/demo/sys/user/testPrint",
dataType: 'json',
success: function (result) {
if (result) {
mysendprint(result);
}
},
error: function () {
Alert("系统异常,请稍后重试!");
}
})
});
function mysendprint(input) {
var ip="127.0.0.1";
var port="12345";
var strJson1 ='${inventoryResultStr}';
var formatData = JSON.stringify(input);
$.post("http://"+ip+":"+port+"/printreport",
{
"ReportType": encodeURIComponent("gridreport"), /*报表类型 gridreport fastreport 为空 将默认为gridreport */
"ReportName": encodeURIComponent("testUser.grf"), /*报表文件名 testUser */
"ReportVersion": 1, /*可选。报表版本, 为空则默认1 如果本地报表的版本过低 将从 ReportUrl 地址进行下载更新*/
//"ReportUrl": encodeURIComponent("http://111.67.202.157:9099/report/PosTicket.grf"), /*可选。为空 将不更新本地报表 , 如果本地报表不存在可以从该地址自动下载*/
"ReportUrl": encodeURIComponent(""), /*可选。为空 将不更新本地报表 , 如果本地报表不存在可以从该地址自动下载*/
"Copies": 1, /*可选。打印份数,支持指定打印份数。默认1份,如果为零,不打印,只返回报表生成的pdf,jpg等文件*/
"PrinterName": encodeURIComponent($("#PrinterS option:selected").text()), /*可选。指定打印机,为空的话 使用默认打印机, 请在 控制面板 -> 设备和打印机 中查看您的打印机的名称 */
"PrintOffsetX": 0, /*可选。打印右偏移,单位厘米。报表的水平方向上的偏移量,向右为正,向左为负。*/
"PrintOffsetY": 0, /*可选。打印下偏移,单位厘米。 报表的垂直方向上的偏移量,向下为正,向上为负。*/
//"token": encodeURIComponent("aa"), /*可选。只要token值在列表中 方可打印*/
"taskId": encodeURIComponent("1234567"), /*可选。多个打印任务同时打印时,根据该id确定返回的是哪个打印任务。 */
//"Parameter": encodeURIComponent(input.parameter),
"Field": encodeURIComponent('[' ///*字段, type ftBlob (base64格式) ,ftString ftInteger ftBoolean, ftFloat, ftCurrency,ftDateTime, size (ftString 设置为实际长度,其他的设置为0,例如 ftInteger ftBlob 等设置为0 )
+'{"type": "ftString", "name": "name","size": 255,"required": false},'
+'{"type": "ftString", "name": "email","size": 255,"required": false},'
+'{"type": "ftString", "name": "mobile","size": 255,"required": false},'
+'{"type": "ftString", "name": "loginName","size": 255,"required": false},'
+'{"type": "ftString", "name": "no","size": 255,"required": false},'
+']'),
"Data": encodeURIComponent(formatData),
},
function(data){
data = decodeURIComponent(data);
if(data==""){
alert("连接HttpPrinter失败");
}else{
//alert(data);
var obj = JSON.parse(data);
//alert(obj.status);
if(obj.status=="ok"){
alert("打印成功");
}else{
alert("打印失败:"+obj.data);
}
var result=JSON.parse(data);
console.log(data);
//alert(result.data);
window.open(result.data,'_blank');
}
});
}
})
</script>
- 因为只是初步集成,后台的业务只是很简单的数据返回,需要注意的一点是,前台在接收返回的json数据的时候,每一个bean的字段正确或者字段多了都是可以正常运行的,但是如果框架设置了字段为null不返回json的话,在打印的时候会报错。可以使用@JsonSerialize注解进行配置
- 代码里只是返回了一个装着User的List对象,这个是我测试偷懒的方式,正确的返回方式应该写一个Entity类来装Parameter、Field、Data字段(参考里的文章就是用的这种方式,但可惜没有源码),然后返回给前台进行配置。我的代码里没有用到Parameter,而Field是直接写死的,只有Data是从后台获取的。另外后台获取的Data是在前台是一个对象,需要先用JSON.stringify(input)方法转换成json字符串。