1.创建替换字段实体类
package io.renren.dto;
import lombok.Data;
/**
* 台风快报内容模板参数DTO
*/
@Data
public class StormPdfContentTemplateParamsDTO {
/**
* 当前时间
*/
private String nowTime;
/**
* 台风ID
*/
private String stormId;
/**
* 台风名称
*/
private String stormName;
/**
* 台风类型
*/
private String stormType;
/**
* 登陆地址
*/
private String address;
/**
* 台风中心位置
*/
private String centerPosition;
/**
* 登陆日期
*/
private String loginDate;
/**
* 台风编号
*/
private String stormNumber;
/**
* 台风等级
*/
private String stormLevel;
/**
* 台风风力
*/
private String speedLevel;
/**
* 台风发布时间
*/
private String pubTime;
/**
* 经度
*/
private String JD;
/**
* 纬度
*/
private String WD;
/**
* 台风附件最大风速
*/
private String windSpeed;
/**
* 台风移动速度
*/
private String moveSpeed;
/**
* 台风移动方向
*/
private String moveDirection;
/**
* 台风路径图
*/
private String imageUrl;
}
2.编写实现类
获取需要填充和替换的字段内容。
@Override
public String getContentTemplate(String tfTywysbm, String stormName) {
StormPdfContentTemplateParamsDTO paramsDTO = new StormPdfContentTemplateParamsDTO();
paramsDTO.setStormName(stormName);
paramsDTO.setStormId(tfTywysbm);
//调用和风API获取台风预报信息
String stormMessage = hfWeatherSDKUtil.hfWeatherTfSkAndLj(tfTywysbm);
JSONObject jsonObject = JSON.parseObject(stormMessage);
JSONObject storm = null;
String time = null;
if (jsonObject.getString("isActive").equals("1")) {
storm = jsonObject.getJSONObject("now");
time = timeFormat(storm.getString("pubTime"));
} else {
JSONArray s = jsonObject.getJSONArray("track");
//获取最后一条更新轨迹
storm = JSON.parseObject(s.get(s.size() - 1).toString());
time = timeFormat(storm.getString("time"));
}
//自定义时间字符串格式
paramsDTO.setPubTime(time);
paramsDTO.setJD(storm.getString("lon"));
paramsDTO.setWD(storm.getString("lat"));
String stormType = getStormType(storm.getString("type"));
paramsDTO.setStormType(stormType);
paramsDTO.setWindSpeed(storm.getString("windSpeed"));
//台风预报等级
String stormLevel = getStormLevel(paramsDTO.getWindSpeed());
paramsDTO.setStormLevel(stormLevel);
paramsDTO.setMoveSpeed(storm.getString("moveSpeed"));
String direction = replaceDir(storm.getString("moveDir"));
paramsDTO.setMoveDirection(direction);
//TODO 获取台风路径图,暂时使用静态图片
// String imageUrl = "http://image.nmc.cn/product/2024/09/28/TCBU/medium/SEVP_NMC_TCBU_SFER_EME_ACWP_L89_0W24180010_20240928080000102.JPG?v=1727487426884";
// paramsDTO.setImageUrl(imageUrl);
String expressNews = WordConstant.CONTENT_TEMPLATE_STORM_FIRST + WordConstant.CONTENT_TEMPLATE_STORM_SECOND + WordConstant.CONTENT_TEMPLATE_STORM_THIRD;
return StringTools.fillParams(expressNews, paramsDTO);
}
3.编写需要替换的文本
package io.renren.constant;
/**
* word常量
* <img src=""/>
*/
public final class WordConstant {
/**
* 台风快报内容模板--第一段
* 2024年XX月XX日XX时XX分,XXXX台风预计在XX省XX市登陆(北纬XX度,东经XX度),XXXX台风强度等级为XXXX
*/
public static final String CONTENT_TEMPLATE_STORM_FIRST = "" +
"<p style=\"text-indent:2em;\">\n" +
"#{[pubTime]},#{[stormName]}台风预计在#{[address]}(北纬#{[WD]},北纬#{[JD]})登陆,#{[stormName]}台风强度等级为#{[stormType]}。现将有关情况报告如下:\n" +
"</p>";
public static final String CONTENT_TEMPLATE_STORM_SECOND = "" +
"<p style=\"text-indent:2em;\">\n" +
"一、#{[stormName]}台风信息\n" +
"</p>" +
"<p style=\"text-indent:2em;\">\n" +
"第#{[stormNumber]}号台风“#{[stormName]}”(#{[stormLevel]})的中心#{[pubTime]}位于#{[centerPosition]},中心附近最大风力有#{[stormLevel]}(#{[windSpeed]}米/秒)。预计,“#{[stormName]}”将以每小时#{[moveSpeed]}公里左右的速度向#{[moveDirection]}方向快速移动," +
"强度变化不大,#{[loginDate]}日晚上移入#{[address]},并将于#{[loginDate]}在#{[address]}地点登陆(#{[stormType]},风力#{[stormLevel]},风速#{[windSpeed]}米/秒),之后强度逐渐减弱。\n" +
"</p>";
public static final String CONTENT_TEMPLATE_STORM_IMAGE = "" +
"<img src=\"#{[imageUrl]}\" style=\"max-width: 100%; height: auto; display: block;\" alt=\"#{[stormName]}台风路径图\">\n";
public static final String CONTENT_TEMPLATE_STORM_THIRD = "" +
"<p style=\"text-indent:2em;\">\n" +
"二、通信情况\n" +
"</p>" +
"<p style=\"text-indent:2em;\">\n" +
"根据铁塔大数据系统分析,#{[address]}铁塔离线、停电率较震前有无明显变化。台风周边区县有无基站退服。 \n" +
"</p>" +
"<p style=\"text-indent:2em;\">\n" +
"三、受影响区域\n" +
"</p>" +
"<p style=\"text-indent:2em;\">\n" +
"受台风影响的#{[address]}地区。 \n" +
"</p>";
}
4.编写内容替换的工具类,实现内容替换功能
目的:将一个对象(bean
)的字段值动态地插入到一个字符串模板(value
)中。通过使用反射和Spring Expression Language,它提供了一种灵活的方式来构建动态字符串,这在生成动态SQL查询、构建动态消息模板等场景中非常有用。不过,需要注意的是,反射和SpEL的使用可能会带来一定的性能开销,并且需要谨慎处理异常和安全性问题。
@SneakyThrows
public static String fillParams(String value, Object bean){
Map<String, String> params = new HashMap<>();
for (Field field : bean.getClass().getDeclaredFields()) {
field.setAccessible(true);
params.put(field.getName(), String.valueOf(field.get(bean)));
}
ExpressionParser parser = new SpelExpressionParser();
TemplateParserContext parserContext = new TemplateParserContext();
return parser.parseExpression(value,parserContext).getValue(params, String.class);
}
代码解释:
它使用了Lombok的@SneakyThrows
注解以及Spring Expression Language (SpEL)来填充一个字符串模板中的参数。
- 创建并填充参数映射:
- 使用
HashMap<String, String>
创建一个名为params
的映射,用于存储bean
对象的字段名和对应的字段值。 - 通过反射遍历
bean
对象的所有声明字段(包括私有字段),将每个字段设置为可访问(field.setAccessible(true)
),并将字段名和字段值(转换为字符串)添加到params
映射中。
- 使用
- 使用SpEL解析和填充字符串:
- 创建一个
ExpressionParser
对象(这里使用的是Spring的SpelExpressionParser
),用于解析SpEL表达式。 - 创建一个
TemplateParserContext
对象,虽然在这个特定的例子中并没有直接使用到它的特定功能(主要用于更复杂的模板解析场景),但它是解析表达式时的一个必需参数。 - 使用
ExpressionParser
的parseExpression
方法解析传入的value
字符串(可能包含SpEL表达式),并将解析后的表达式与前面创建的params
映射一起传递给getValue
方法。getValue
方法使用params
映射中的值来替换value
字符串中的占位符,并返回最终的字符串结果。
- 创建一个