taglib-html:浏览器会自动解析

本文详细介绍了Struts框架中HTML标签的应用,包括html、base、link、form、text等标签的功能及使用方法,同时阐述了如何在JSP页面中创建链接、表单和进行验证操作。

引用:

<%@  taglib uri="http://jakarta.apache.org/struts/tags-html" profix="html"%>

jsp页面使用

<html:html> 生成一个<html>元素

<html:base> 生成一个<base>元素
	<html:base href="<%-basePath%>"生成当前页面的绝对路径,意义不大
<html:link> 生成一个<a>元素
	<a href="/loginform/login.do">login</a>
	
	由struts-config.xml中的全局转发创建链接
		<global-forwards>
			<forwards name="index" path="/index.jsp"/>
		</global-forwards>
	在jsp页面创建链接
		<html:link forwards="index">
			Link to ActionForward
		</html-link>
		
	在url全路径创建链接:提供全路径
		<html:link href="http://www.baidu.com">  
			Link to baidu
		</html-link>
		
	由当前页面的相对路径创建链接
		<html-link page="/HtmlBasic.do">
			Link to page
		</html-link>
<html:rewrite>标签<html-link>URI部分

<html:img>生成一个<img>元素



<html:form>生成一个<form> 元素
	jsp页面创建form属性
		<html:form action="/register">
		</html:form>
	
	Formbean里面添加类ClientForm
	
	struts-config里面配置文件
		<form-beans >
			<form-bean name="clientForm" type="com.amaker.struts.form.ClientForm" />
		</form-beans>		
<html:text>生成一个文本的Input元素
	username<html:text property="username"/><br/>
	
	Formbean里面Form类添加属性:username
	
<html:hidden>生成一个文本的Input元素
	<html:hidden property="userid"/>
	
	Formbean里面Form类添加属性:userid
<html:submit>生成一个文本的Input元素
	<html:submit value="提交"/>
	
<html:cancel>生成一个文本的Input元素
	<html:cancel value="取消"/>
	
<html:reset>生成一个文本的Input元素
	<html:reset value="重置">
	
<html:checkbox>生成一个有单选左右的按钮,比如协议是否同意的时候选择
	jsp页面创建
		ispay:<html:checkbox property="pay"/>
		
	Formbean里面Form类添加属性:
		private String pay  
		打钩:  on
		不打勾: 什么都没有
	了解,用的不多
	
<html:multibox>生成一个多选按钮
	jsp页面
		hobby<html:multibox property="hobby" value="1">reading<br/>
			 <html:multibox property="hobby" value="2">swing
		 
	Formbean里面Form类添加属性:
		private String[] hobby
	
<html:radio>生成一个有单选按钮
	jsp页面
		gender:<html:multibox property="gender" value="female"/>female<br/>
		<html:multibox property="gender" value="man"/>man

	Formbean里面Form类添加属性:
		private String  gender
		
<html:select>生成一个下拉列表
	在jsp页面
		<html:select property="position">
			<html:option value="1">CEO<html:option>
			<html:option value="2">CFO<html:option>
			<html:option value="3">PM<html:option>
	
	Formbean里面Form类添加属性:
		private String  position
		
	从数据库获得值生成响应标签
	FormBean里面有Position(String id,String name)
	jsp的<head>里面测试,实际应该从数据库里拿到list,在action里面赋值
	顶部
	<%@ language="java" import="com.amaker.bean.*,java.util.*"%>
		head里面——<%
			Link list=new ArrayList();
			for(int i=0;i<10;i++){
				Position posi=new Position(i,"position"+i);
				list.add(posi);
			}
			request.setAttribute("PL",list);
		%>
	
	jsp的<body>里面
		<html:options collection="PL" property="id" labelProperty="name"/>
		id对应formbean里面position表单的id,name对应的值
<html:errors>
	jsp页面
		<html:errors property="username"/>
		
	手动验证:
		FormBean的类里面继承ActionForm,需要重写一个 validate方法,只有这个方法通过,才可以执行Action,大部分时间写在这里
		顺序:
			先xml里面的*.do,找到struts-config.xml里面的path跳转路径,然后执行name的FromBean获得值,
			获得值之后验证信息,最后执行Action
		public ActionErrors validate(...){
			ActionErrors errors=new ActionErrors();
			if(username==null||username.trim().equals("")){
				errors.add("username",new ActionMessage("login.username"));
				//"username"标签,响应jsp里面的错误标签  login.username在资源配置文件中的提示错误信息
				return errors;
			}
			return null;
		}
		return errors 返回struts-config里面的input路径
		如果在Action里面做验证,如果错误需要 返回:mapping.getInputforward();
	
	
	自动验证:
	1 添加struts后项目内需要添加2个jar包:commos-validator.jar  和 jakarta-oro.jar
	2 添加2个xml配置文件: validation.xml 和validator-rules.xml
		validation.xml可以去structs里面的apps/struts-blank-1.3.8\WEB-INF下面找模板,如果模板里面有<formset>"另"一个列子,则删除,否则可能会报错
	3 在Struct-config.xml配置文件中加载自动验证工具类和配置文件,这段话在validator-rules.xml里面有:
		<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
		<set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
		</plug-in>
	4 formBean要继承ValidatorForm
	5 在validation中声明验证
	6 调用
		在ApplicationResources.properties配置文件里:
			errors.minlength={0} can not be less than {1} characters.
			
			login.username=Username
			
		validation.xml
			<formset>
				<form name="loginForm">    //name是struts-config.xml里面<form-bean>的name
					<field property="username" depends="required,maxlength">
						<arg key="loginForm.username" position="0"/>
						<arg name="maxlength" key="${var:maxlength}" resource="false" position="1"/>
							<var>
								<var-name>maxlength</var-name>
								<var-value>20</var-value>
							</var>
					</field>
					<field property="age" depends="required,intRange">
						<arg key="loginForm.username" position="0"/>
						<arg name="intRange" key="${var:minlength}" resource="false" position="1"/>
						<arg name="intRange" key="${var:manlength}" resource="false" position="2"/>
							<var>
								<var-name>mixlength</var-name>
								<var-value>1</var-value>
							</var>
							<var>
								<var-name>maxlength</var-name>
								<var-value>150</var-value>
							</var>
					</field>
				</form>
			</formset>
			name:验证FormBean名称,struts-config里面定义的名称
			property:验证FormBean的属性
			depends:验证规则的逻辑名称
			key:验证提示信息
			resource:
				true:来自资源文件
				false:直接设置
			var:为变量传递参数
	
		loginForm需要继承 ValidatorForm
		
		
	validator:
		required,minlength,maxlength,mask:正则表达式,byte,short,integer,long,float,double,date,
		intRange,floatRange,doubleRange,creditCard,email,url
		
	自定义验证:验证两个字段是否相同
		配置文件:
			<field property="password" depends="required,twofields">
				<arg key="memberRegisterForm.password" position="0"/>
				<arg name="twofields" key="memberRegisterForm.password2" position="1"/>
					<var>
						<var-name>secondProperty</var-name>
						<var-value>password2</var-value>
					</var>
			</field>
		写一个类:
			public static boolean validateTwoFields(Object bean,ValidatorAction va,Field field,ActionMessages errors,HttpServletRequest request){
				String value=ValidatorUtils.getValueAsString(bean,field.getProperty());
				String property2=field.getVarValue("secondProperty");
				String value2=ValidatorUtils.getValueAsString(bean,property2);
				if(!GenericValidatior.isBlankOrNull(value)){
					try{
						if(!value.equals(value2)){
							errors.add(field.getKey(),Resources.getActionMessage(request,va,field));
							return false;
						}
					}catch(Exception e){
						errors.add(field.getKey(),Resources.getActionMessage(request,va,field));
						return false;
					}
				}
				return true;
			}

File

<html:file>生成一个<input type=file>元素来支持文件上传
	Jsp页面,必须是enctype="multipart/form-data",一个字都不能差
		<html:form action="HtmlFile.do" enctype="multipart/form-data">
			File:<html:file property="file"/>
		</html:form>
		
	Formbean里面Form类添加属性
		private FormFile file;
		
	eg:
	FormFile file=uploadForm.getFile();
	InputStream in=file.getInputStream();
	String fileName=file.getFileName();
	int size=file.getFileSize();
	//得到真实路径
	String path=super.servlet.getServletContext().getRealPath("/upload");
	OutputStream out=new FileOutputStream(path+"\\"+fileName);
	byte[] buf=new byte[size];
	in.read(buf);
	out.write(buf);
	in.close();
	out.close();



解决验证信息中的中文乱码问题

创建build.xml文件
	调用native2ascii.exe进行转码
	代码:
	<project>
		<target name="i18n">
			<native2ascii dest="com/amaker/struts" src="com/amaker/struts/temp" encoding="UTF-8" includes="ApplicationResources*.properties"/>
		</target>
	</project>



<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page isELIgnored="false" %> <html> <head> <title>街霸6角色列表</title> <style> .role-card { border: 1px solid #ccc; border-radius: 8px; padding: 15px; margin: 15px; display: inline-block; width: 280px; vertical-align: top; text-align: center; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .role-image { width: 100%; height: 200px; object-fit: cover; border-radius: 4px; margin-bottom: 10px; } .role-info { text-align: left; margin-bottom: 15px; } .detail-btn { padding: 8px 20px; background-color: #2c3e50; color: white; border: none; border-radius: 4px; cursor: pointer; text-decoration: none; } .detail-btn:hover { background-color: #34495e; } </style> </head> <body> <h1 style="text-align: center;">街霸6列表</h1> <c:forEach items="${characterList}" var="character"> <div class="role-card"> <!-- 直接使用后端解析好的纯URL,无复杂表达式 --> <img class="role-image" src="${character.pureImageUrl}" alt="${character.characterName}"> <div class="role-info"> <h3>${character.characterName}</h3> <p>出身:${character.origin}</p> <p>格斗风格:${character.fightingStyle}</p> <!-- 修复EL表达式条件优先级(添加括号) --> <p>难度:<span style="color: ${character.difficulty == '新手' ? 'green' : (character.difficulty == '进阶' ? 'orange' : 'red')}">${character.difficulty}</span></p> </div> <a href="/characterDetail?characterId=${character.characterId}" class="detail-btn">查看详情</a> </div> </c:forEach> </body> </html> (HTTP状态 404 - 未找到 类型 状态报告 描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。 Apache Tomcat/10.1.48)
11-27
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ page language="java" import="app.system.Util"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="renderer" content="webkit"> <base href="<%=basePath%>" /> <link href="css/bootstrap.min.css?v=3.3.5" rel="stylesheet"> <link href="css/font-awesome.min.css?v=4.4.0" rel="stylesheet"> <link href="css/animate.min.css" rel="stylesheet"> <link href="css/style.min.css" rel="stylesheet"> <script src="js/jquery-2.1.1.min.js"></script> <script src="js/custom/jqueryTableyp1.js"></script> <style type="text/css"> body { font-family: "SimSun-ExtB", "宋体"; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } table{ margin: 0 auto; } </style> <script type="text/javascript"> $(function() { $('table').each(function() { $("#t2").height(430 - $("#gg").height()+15); }); window.print(); }); </script> </head> <body class="tablebody"> <div style="width:710px;border:1px solid #fff;margin: 0px auto;"> <div style="border:0px solid #fff;margin: 0px auto;"> <div id="headerInfo" > <table style="width:98%; margin-top: 10px;height:90px;" border="0" id="bt" cellpadding="0" cellspacing="0" > <%-- <tr> <td align="right" colspan="2"><img src="brandCode!create1w.do?barcode=${bean.lccb_jybh }" style="width:180px;height:100%" /> </tr> --%> <tr> <td align="center" colspan="2"><font style="letter-spacing:1px;font-family:宋体;font-size:36px;font-weight: 600; ">呼和浩特市检验检测中心检验报告 </font></td> </tr> <tr> <td style="height:13px;" colspan="2"></td> </tr> <tr> <td align="right" colspan="2"> <font style="letter-spacing:3px;font-family:宋体;font-size:16px;font-weight: bold;; ">${map.skh }</font> </td> </tr> <tr> <td style="font-family:宋体;font-size:14px;vertical-align: bottom;">报告书编号:<font style="font-size: 16px;font-weight: 600;">${bean.lccb_jybh}</font> </div></td> <td style="font-family:宋体;font-size:14px;vertical-align: bottom;" align="right" colspan="2" ><p class="pageNum" style="font-size: 14px;text-align: right;margin: 0px;padding: 0px;"></p></td> </tr> </table> <table style="width:98%;font-size: 14px;padding: 0px;line-height:16px;border-bottom: none" bordercolor="#000" border="1" class="basicTable"> <colgroup> <col width="15%" > <col width="35%" > <col width="15%" > <col width="35%" > </colgroup> <tr> <td align="center" height="35px">检品名称</td> <td class="data" style="padding-left:5px;">${bean.lccb_jpmc}</td> <td align="center" height="35px">检品编号</td> <td class="data" align="left" height="35px">${bean.lccb_jybh}</td> </tr> <tr> <td align="center" height="35px">批        号</td> <td class="data" style="padding-left:5px;word-wrap:break-word; word-break:break-all;">${bean.lccb_ph }</td> <td align="center">规        格</td> <td class="data" style="padding-left:5px;word-wrap:break-word; word-break:break-all;">${bean.lccb_gg}</td> </tr> <tr> <td align="center" height="35px">标示生产单位<br>或产地</td> <td class="data" height="35px">${bean.lccb_scdw}</td> <td align="center" height="35px">包装规格</td> <td class="data" height="35px">${bean.lccb_baozfl }</td> </tr> <tr> <td align="center" height="35px">生产日期</td> <td class="data" style="padding-left:5px;">${bean.lccb_scrq }</td> <td align="center" height="35px">有效期至</td> <td class="data" align="left" height="35px">${bean.lccb_yxq }</td> </tr> <tr> <td align="center" height="35px">供样单位名称<br>及地址</td> <td class="data" style="padding-left:5px;"> <c:choose> <c:when test="${bean.lccb_gydw eq '/' && bean.lccb_gydwdz eq '/'}"> / </c:when> <c:otherwise> ${bean.lccb_gydw}${bean.lccb_gydwdz} </c:otherwise> </c:choose> </td> <td align="center">检品数量</td> <td class="data" style="padding-left:5px;word-wrap:break-word; word-break:break-all;">${bean.lccb_jpsl}</td> </tr> <tr> <td align="center" height="35px">检验目的</td> <td class="data" style="padding-left:5px;">${bean.lccb_jymdxl}</td> <td align="center" >有效期(至)</td> <td class="data" style="padding-left:5px;">${empty bean.lccb_yxq?"/":bean.lccb_yxq}</td> </tr> <tr> <td align="center" height="35px">委托单位名称<br>及地址</td> <td class="data" style="padding-left:5px;"> <c:choose> <c:when test="${bean.lccb_wtdw eq '/' && bean.lccb_wtdwdz eq '/'}"> / </c:when> <c:otherwise> ${bean.lccb_wtdw}${bean.lccb_wtdwdz} </c:otherwise> </c:choose> </td> <td align="center" >样品状态</td> <td class="data" style="padding-left:5px;">${bean.lccb_chouyfyzt}</td> </tr> <tr> <td align="center" height="35px">被抽样单位</td> <td class="data" style="padding-left:5px;word-wrap:break-word; word-break:break-all;">${bean.lccb_bcydw}</td> <td align="center">留样数量</td> <td class="data" style="padding-left:5px;word-wrap:break-word; word-break:break-all;">${bean.lccb_lysl}</td> </tr> <tr> <td align="center" height="35px">检验目的</td> <td class="data" style="padding-left:5px;word-wrap:break-word; word-break:break-all;">${bean.lccb_jymddl }<c:if test="${not empty bean.lccb_jymdxl }"> (${bean.lccb_jymdxl }) </c:if></td> <td align="center">留样签收</td> <td class="data" style="padding-left:5px;word-wrap:break-word; word-break:break-all;">${bean.lccb_lyqs}</td> </tr> <tr> <td align="center" height="35px">检验项目</td> <td class="data" style="padding-left:5px;"><c:choose> <c:when test="${ not empty bean.lccb_jyxmqt }"> ${bean.lccb_jyxmqt } </c:when> <c:otherwise> ${bean.lccb_jyxm } </c:otherwise> </c:choose> </td> <td align="center" height="25px">经办人</td> <td class="data" style="padding-left:5px;">${bean.lccb_jbr}</td> </tr> <tr style="border-bottom: none"> <td style="border-bottom: none" align="center" height="35px">检验依据</td> <td class="data" colspan="3" style="padding-left:5px;border-bottom: none"> <c:choose> <c:when test="${ not empty bean.lccb_jyxmqt }"> ${bean.lccb_jyxmqt } </c:when> <c:otherwise> ${bean.lccb_jyxm } </c:otherwise> </c:choose> </td> </tr> </table> </div> <table id="tabContent" style="width:98%;font-size: 14px;border-collapse:collapse;" border="1" > <thead> <tr> <td width="1.5%" style="border:0;"></td> <td width="18%" align="left" style="border:0;padding-left:15px;" height="25px">检验项目</td> <td width="36%" align="left" style="border:0;padding-left:30px;">标准规定</td> <td width="26%" align="left" style="border:0;padding-left:25px;">检验结果</td> <td width="1.5%" style="border:0;"></td> </tr> </thead> <tbody> <c:set var="jydl" value=""></c:set> <c:forEach items="${map.list }" var="subject"> <c:choose> <c:when test="${subject.lcs_jydl=='000'||subject.lcs_jydl=='/'}"> <tr> <td style="border:0;"></td> <td align="left" valign="top" class="td1" style="border:0;padding-left:13px;">    ${subject.lcs_jyxm }</td> <td align="left" valign="top" class="td1" style="border:0;padding-left:30px;word-break:break-all;">${subject.lcs_bzgd }</td> <td align="left" valign="top" class="td1" style="border:0;padding-left:25px;height:20px;">${subject.lcs_jyjg }<c:if test="${fn:contains(subject.lcs_jyjl ,'不') }">(不符合规定)</c:if></td> <td style="border:0;"></td> </tr> </c:when> <c:otherwise> <tr> <td style="border:0;"></td> <td align="left" class="td1" style="border:0;height:20px;padding-left:13px;">【${subject.lcs_jydl }】</td> <td align="left" class="td1" style="border:0;"></td> <td align="left" class="td1" style="border:0;"></td> <td style="border:0;"></td> </tr> <tr> <td style="border:0;"></td> <td align="left" class="td1" valign="top" style="border:0;padding-left:13px;">    ${subject.lcs_jyxm }</td> <td align="left" class="td1" valign="top" style="border:0;padding-left:30px;word-break:break-all;">${subject.lcs_bzgd }</td> <td align="left" class="td1" valign="top" style="border:0;padding-left:25px;height:20px;">${subject.lcs_jyjg } <c:if test="${fn:contains(subject.lcs_jyjl ,'不') }">(不符合规定)</c:if> </td> <td style="border:0;"></td> </tr> </c:otherwise> </c:choose> </c:forEach> </table> <table style="width:98%;margin-top:0px; font-size: 14px;border-collapse:collapse;border: 1px solid black;border-top: 0px" id="dbtable" border="1" > <tr> <td style="padding-left: 1%" height="30px"> 备注: ${bean.lccb_bgsbz }</td> </tr> <tr> <td style="padding-left: 1%" height="30px"> 结论: <c:choose> <c:when test="${bean.lccb_zzjlyj == '/' || bean.lccb_zzjl =='/'}"> ${bean.lccb_zzjlyj },结果${bean.lccb_zzjl }。 </c:when> <c:otherwise> ${bean.lccb_zzjlyj },结果${bean.lccb_zzjl }。 </c:otherwise> </c:choose> </td> </tr> <c:if test="${not empty map.flagsy }"> <tr> <td height="60px"><font style="padding-left: 1%">批准: </font> <font style="padding-left: 30%">审核: </font> <font style="padding-left: 30%">主检: </font></td> </tr> </c:if> <c:if test="${ empty map.flagsy }"> <tr> <td height="50px"> <font style="padding-left: 1%">批准:<img width="80px" height="45px" alt="" src="<%=basePath%>sign/${bean.lccb_qianfr }.png"></font> <font style="padding-left: 20%">审核:<img width="80px" height="45px" alt="" src="<%=basePath%>sign/${bean.lccb_ywkzrsh }.png"></font> <font style="padding-left: 20%">主检:<img width="80px" height="45px" alt="" src="<%=basePath%>sign/${bean.lccb_zjkszrsh }.png"></font> </td> </tr> </c:if> </tbody> </table> </div> </div> </body> <script type="text/javascript"> $(function() { rowHeight(); window.print(); }); $(".data").each(function(){ var val = $(this).text().trim(); if(!val)$(this).text("/") }) function rowHeight() { $("#tabContent") .printTable( { mode : "rowHeight", header : "#headerInfo", footer : "#footerInfo", breakClass : "PageNext", pageNumStyle : "第 #p 页 共 #P 页", pageNumClass : ".pageNum",//页码 startPage : 1,//从第几页开始 pageHeight : 1090, iskb : true,//空白位置中间false下边true isyc : false,//是否有隐藏内容 isscdl : true,//第一行是否添加大类 endkbwz : "<p style='text-align: center;width:100%;margin:0px;padding:0px;'>----以下空白----</p>", //kbwz:"", autoheight : false, kbwz : "vertical-align: top;border:0px;'><p style='text-align: center;width:100%;margin:0px;padding:0px;'>----接下一页----</p>", jsyt: "vertical-align: top;border:0;border-right:1px solid #000;height:23px'><p style='text-align: center;width:100%;margin:0px;'>----接上一页----</p>", ycnr : ".yc",//要隐藏的内容 dbgd : "#dbtable"//没有统一底部时调用 }); $(".pageNum:visible").each(function(i) { var count = $(".pageNum:visible").length; $(this).html("第 " + (i + 1) + " 页,共 " + count + " 页"); }); } </script> </html>上述代码哪里出现了问题导致检验项目格式混乱并且该如何修改
最新发布
12-11
<%@ page language=“java” import=“java.util.*” pageEncoding=“gbk”%> <%@ taglib uri=“http://java.sun.com/jsp/jstl/functions” prefix=“fn” %> <%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c”%> <% String path = request.getContextPath(); String basePath = request.getScheme()+“😕/”+request.getServerName()+“:”+request.getServerPort()+path+“/”; %> <!DOCTYPE html> <html> <head> <meta charset="gbk"> <meta name="renderer" content="webkit"> <title>PDF在线盖章系统</title> <meta http-equiv="X-UA-Compatible" content="IE=edge,Chrome=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <link rel="stylesheet" href="layui/css/layui.css" media="all"> <link rel="stylesheet" type="text/css" href="layuis/css/common_main.css"/> <script type="text/javascript" src="jquery/jquery-1.7.2.min.js"></script> <script src="layui/layui.all.js" charset="gbk"></script> <script type="text/javascript" src="js/pdf/pdf.min.js" charset="gbk"></script> <script type="text/javascript" src="js/pdf/jspdf.umd.min.js" charset="gbk"></script> <script type="text/javascript" src="js/pdf/pdf.worker.min.js" charset="gbk"></script> <style type="text/css"> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: #f5f7fa; color: #333; line-height: 1.6; padding: 20px; } .container { max-width: 1200px; margin: 0 auto; background: white; border-radius: 12px; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1); overflow: hidden; } header { background: linear-gradient(135deg, #2c3e50, #4a6491); color: white; padding: 20px; text-align: center; } h1 { font-size: 28px; margin-bottom: 10px; } .description { font-size: 16px; opacity: 0.9; max-width: 600px; margin: 0 auto; } .main-content { display: flex; padding: 20px; gap: 20px; } .left-panel { flex: 0 0 250px; display: flex; flex-direction: column; gap: 20px; } .control-panel { background: #f8f9fa; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); } .button { padding: 12px; border: none; border-radius: 6px; cursor: pointer; font-weight: 600; transition: all 0.3s; width: 100%; margin-bottom: 10px; } .secondary-btn { background: #4a6491; color: white; } .secondary-btn:hover { background: #3a547e; } .secondary-btn2 { background: #27ae60; color: white; } .secondary-btn2:hover { background: #219653; } .secondary-btn3 { background: #e74c3c; color: white; } .secondary-btn3:hover { background: #c0392b; } .stamp-panel { background: #f8f9fa; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); } .stamp-panel h3 { margin-bottom: 15px; color: #2c3e50; border-bottom: 1px solid #ddd; padding-bottom: 10px; } .stamp-item { padding: 12px; background: white; border: 2px dashed #4a6491; border-radius: 6px; text-align: center; cursor: grab; margin-bottom: 10px; transition: all 0.3s; } .stamp-item:hover { background: #e8f0fe; transform: translateY(-2px); } .pdf-viewer { flex: 1; background: #f8f9fa; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); } .viewer-header { padding: 15px; background: #4a6491; color: white; display: flex; justify-content: space-between; align-items: center; } .canvas-container { position: relative; overflow: auto; height: 600px; background: #525659; display: flex; justify-content: center; padding: 20px; } #pdfCanvas { box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); } .loading { text-align: center; padding: 40px; color: #777; font-size: 18px; } .page-controls { display: flex; justify-content: center; padding: 15px; background: #e8e8e8; gap: 15px; } .page-btn { padding: 8px 16px; background: #4a6491; color: white; border: none; border-radius: 4px; cursor: pointer; } .page-info { padding: 8px 16px; background: white; border-radius: 4px; min-width: 100px; text-align: center; } .stamp-indicator { position: absolute; width: 100px; height: 100px; border: 2px dashed #ff0000; border-radius: 50%; background: rgba(255, 0, 0, 0.1); display: flex; align-items: center; justify-content: center; font-weight: bold; color: #ff0000; pointer-events: none; display: none; } footer { text-align: center; padding: 20px; color: #777; font-size: 14px; border-top: 1px solid #eee; } @media (max-width: 768px) { .main-content { flex-direction: column; } .left-panel { flex: 1; width: 100%; } .canvas-container { height: 400px; } } /* 印章样式 */ .signature-stamp { color: #1a73e8; border: 2px solid #1a73e8; } .approval-stamp { color: #0b8043; border: 2px solid #0b8043; } .review-stamp { color: #e67c73; border: 2px solid #e67c73; } .date-stamp { color: #8e24aa; border: 2px solid #8e24aa; } .stamp-on-canvas { position: absolute; width: 100px; height: 100px; border: 2px solid; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; cursor: pointer; z-index: 10; } .zoom-controls { display: flex; justify-content: center; padding: 10px; background: #e8e8e8; gap: 10px; } .zoom-btn { padding: 6px 12px; background: #4a6491; color: white; border: none; border-radius: 4px; cursor: pointer; } </style> </head> <body> <div class="container"> <div class="main-content"> <div class="left-panel"> <div class="control-panel"> <h3>文档操作</h3> <button id="save-btn" class="button secondary-btn">保存签章</button> <button id="export-btn" class="button secondary-btn2">导出文档</button> <button id="reset-btn" class="button secondary-btn3">重置签章</button> </div> <div class="stamp-panel"> <h3>选择印章</h3> <div class="stamp-item signature-stamp" data-type="signature" data-text="张三"> <div>个人签名</div> </div> <div class="stamp-item approval-stamp" data-type="approval" data-text="已批准"> <div>批准印章</div> </div> <div class="stamp-item review-stamp" data-type="review" data-text="已审核"> <div>审核印章</div> </div> <div class="stamp-item date-stamp" data-type="date" data-text="2023-11-08"> <div>日期印章</div> </div> </div> </div> <div class="pdf-viewer"> <div class="viewer-header"> <h3>文档预览</h3> <div id="doc-info">加载中...</div> </div> <div class="canvas-container"> <div class="loading" id="loading-message">正在加载PDF文档...</div> <canvas id="pdfCanvas"></canvas> <div id="stamp-preview" class="stamp-indicator">印章预览</div> </div> <div class="page-controls"> <button id="prev-page" class="page-btn">上一页</button> <div class="page-info">页码: <span id="page-num">0</span> / <span id="page-count">0</span></div> <button id="next-page" class="page-btn">下一页</button> </div> <div class="zoom-controls"> <button id="zoom-out" class="zoom-btn">缩小</button> <button id="zoom-reset" class="zoom-btn">重置缩放</button> <button id="zoom-in" class="zoom-btn">放大</button> </div> </div> </div> </div> <script> // 设置PDF.js worker pdfjsLib.GlobalWorkerOptions.workerSrc = 'js/pdf/pdf.worker.min.js'; // 全局变量 let pdfDoc = null; let pageNum = 1; let pageRendering = false; let pageNumPending = null; let pdfScale = 1.2; let canvas = document.getElementById('pdfCanvas'); let ctx = canvas.getContext('2d'); let currentStamp = null; let stamps = []; // 预设PDF URL - 可以根据需要修改 const DEFAULT_PDF_URL = decodeURI('${pdfurl}'); // 元素引用 const loadingMessage = document.getElementById('loading-message'); const pageNumElement = document.getElementById('page-num'); const pageCountElement = document.getElementById('page-count'); const docInfoElement = document.getElementById('doc-info'); const prevPageButton = document.getElementById('prev-page'); const nextPageButton = document.getElementById('next-page'); const saveButton = document.getElementById('save-btn'); const exportButton = document.getElementById('export-btn'); const resetButton = document.getElementById('reset-btn'); const stampItems = document.querySelectorAll('.stamp-item'); const stampPreview = document.getElementById('stamp-preview'); const zoomInBtn = document.getElementById('zoom-in'); const zoomOutBtn = document.getElementById('zoom-out'); const zoomResetBtn = document.getElementById('zoom-reset'); // 从URL加载PDF function loadPdfFromUrl(url) { loadingMessage.style.display = 'block'; loadingMessage.textContent = '正在加载PDF文档...'; canvas.style.display = 'none'; pdfjsLib.getDocument(url).promise.then(function(pdf) { pdfDoc = pdf; pageCountElement.textContent = pdf.numPages; docInfoElement.textContent = `已加载 - ${pdf.numPages} 页`; loadingMessage.style.display = 'none'; canvas.style.display = 'block'; // 渲染第一页 pageNum = 1; renderPage(pageNum); }).catch(function(error) { loadingMessage.textContent = '加载PDF失败: ' + error.message; console.error('PDF加载错误:', error); // 尝试备用PDF URL setTimeout(() => { loadingMessage.textContent = '尝试备用PDF文档...'; loadPdfFromUrl(DEFAULT_PDF_URL); }, 2000); }); } // 渲染PDF页面 function renderPage(num) { pageRendering = true; pdfDoc.getPage(num).then(function(page) { const viewport = page.getViewport({ scale: pdfScale }); canvas.height = viewport.height; canvas.width = viewport.width; const renderContext = { canvasContext: ctx, viewport: viewport }; const renderTask = page.render(renderContext); renderTask.promise.then(function() { pageRendering = false; pageNumElement.textContent = num; // 如果存在待处理的页面渲染,立即渲染 if (pageNumPending !== null) { renderPage(pageNumPending); pageNumPending = null; } // 绘制当前页的印章 drawStampsForPage(num); }); }); } // 排队渲染页面 function queueRenderPage(num) { if (pageRendering) { pageNumPending = num; } else { renderPage(num); } } // 上一页 function onPrevPage() { if (pageNum <= 1) return; pageNum--; queueRenderPage(pageNum); } // 下一页 function onNextPage() { if (pageNum >= pdfDoc.numPages) return; pageNum++; queueRenderPage(pageNum); } // 绘制当前页的印章 function drawStampsForPage(pageNumber) { // 清除画布并重新渲染PDF页面 ctx.clearRect(0, 0, canvas.width, canvas.height); // 重新渲染PDF页面 pdfDoc.getPage(pageNumber).then(function(page) { const viewport = page.getViewport({ scale: pdfScale }); const renderContext = { canvasContext: ctx, viewport: viewport }; page.render(renderContext).promise.then(function() { // 绘制印章 stamps.filter(stamp => stamp.page === pageNumber).forEach(stamp => { ctx.font = 'bold 20px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; if (stamp.type === 'signature') { ctx.fillStyle = '#1a73e8'; ctx.strokeStyle = '#1a73e8'; } else if (stamp.type === 'approval') { ctx.fillStyle = '#0b8043'; ctx.strokeStyle = '#0b8043'; } else if (stamp.type === 'review') { ctx.fillStyle = '#e67c73'; ctx.strokeStyle = '#e67c73'; } else if (stamp.type === 'date') { ctx.fillStyle = '#8e24aa'; ctx.strokeStyle = '#8e24aa'; } // 绘制圆形印章 ctx.beginPath(); ctx.arc(stamp.x, stamp.y, 50, 0, Math.PI * 2); ctx.stroke(); // 绘制印章文字 ctx.fillText(stamp.text, stamp.x, stamp.y); // 如果是批准或审核印章,添加额外文字 if (stamp.type === 'approval' || stamp.type === 'review') { ctx.font = 'bold 14px Arial'; ctx.fillText('印章', stamp.x, stamp.y + 20); } }); }); }); } // 缩放功能 function zoomIn() { pdfScale += 0.2; queueRenderPage(pageNum); } function zoomOut() { if (pdfScale > 0.5) { pdfScale -= 0.2; queueRenderPage(pageNum); } } function zoomReset() { pdfScale = 1.2; queueRenderPage(pageNum); } // 初始化事件监听 function initEvents() { // 上一页/下一页按钮 prevPageButton.addEventListener('click', onPrevPage); nextPageButton.addEventListener('click', onNextPage); // 保存、导出、重置按钮 saveButton.addEventListener('click', function() { if (stamps.length === 0) { alert('请先添加印章'); return; } alert('保存成功!共添加了 ' + stamps.length + ' 个印章'); }); exportButton.addEventListener('click', function() { if (stamps.length === 0) { alert('请先添加印章'); return; } alert('导出功能已触发(实际应用中会生成带印章的PDF)'); }); resetButton.addEventListener('click', function() { if (stamps.length === 0) { alert('当前没有印章可重置'); return; } if (confirm('确定要重置所有印章吗?')) { stamps = []; renderPage(pageNum); alert('已重置所有印章'); } }); // 缩放按钮 zoomInBtn.addEventListener('click', zoomIn); zoomOutBtn.addEventListener('click', zoomOut); zoomResetBtn.addEventListener('click', zoomReset); // 印章拖放功能 stampItems.forEach(item => { item.addEventListener('dragstart', function(e) { currentStamp = { type: this.dataset.type, text: this.dataset.text || '' }; // 设置拖放预览图像 stampPreview.textContent = this.dataset.text; stampPreview.style.display = 'block'; // 根据印章类型设置样式 if (currentStamp.type === 'signature') { stampPreview.style.borderColor = '#1a73e8'; stampPreview.style.color = '#1a73e8'; stampPreview.style.background = 'rgba(26, 115, 232, 0.1)'; } else if (currentStamp.type === 'approval') { stampPreview.style.borderColor = '#0b8043'; stampPreview.style.color = '#0b8043'; stampPreview.style.background = 'rgba(11, 128, 67, 0.1)'; } else if (currentStamp.type === 'review') { stampPreview.style.borderColor = '#e67c73'; stampPreview.style.color = '#e67c73'; stampPreview.style.background = 'rgba(230, 124, 115, 0.1)'; } else if (currentStamp.type === 'date') { stampPreview.style.borderColor = '#8e24aa'; stampPreview.style.color = '#8e24aa'; stampPreview.style.background = 'rgba(142, 36, 170, 0.1)'; } e.dataTransfer.setDragImage(stampPreview, 50, 50); }); }); // 画布拖放事件 canvas.addEventListener('dragover', function(e) { e.preventDefault(); if (currentStamp) { const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; stampPreview.style.display = 'block'; stampPreview.style.left = (x - 50) + 'px'; stampPreview.style.top = (y - 50) + 'px'; } }); canvas.addEventListener('dragleave', function() { stampPreview.style.display = 'none'; }); canvas.addEventListener('drop', function(e) { e.preventDefault(); stampPreview.style.display = 'none'; if (currentStamp) { const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const stamp = { type: currentStamp.type, text: currentStamp.text, x: x, y: y, page: pageNum }; stamps.push(stamp); drawStampsForPage(pageNum); } }); } // 初始化 window.onload = function() { initEvents(); // 页面加载后自动加载默认PDF loadPdfFromUrl(DEFAULT_PDF_URL); }; </script> </body> </html>这个代码加载到的pdf就显示两个横线,页码正常
09-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值