1.引入Freemarker坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>2.6.7</version>
</dependency>
2.配置application.yml
spring:
freemarker:
# 后缀名 freemarker 默认后缀为 .ftl ,当然你也可以改成自己习惯的 .html
suffix: .ftl
charset: UTF-8
content-type: text/html
allow-request-override: true
allow-session-override: true
expose-request-attributes: true
expose-session-attributes: true
expose-spring-macro-helpers: true
prefer-file-system-access: false
# 设定模板的加载路径
template-loader-path: file:static/mobile_static/ftl/,classpath:/static/mobile_static/ftl/
settings:
template_update_delay: 1
default_encoding: UTF-8
classic_compatible: true
date_format: yyyy-MM-dd
time_format: HH:mm:ss
datetime_format: yyyy-MM-dd HH:mm:ss
number_format: 0.##
3.定义模板输出路径(application.properties)
out_put_path=C:/Users/Shryu/Study/test/health_project/src/main/resources/static/mobile_static/1
4.使用Freemarker渲染页面
mobile_setmeal.ftl
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../img/asset-favico.ico">
<title>预约</title>
<link rel="stylesheet" href="../css/page-health-order.css" />
</head>
<body data-spy="scroll" data-target="#myNavbar" data-offset="150">
<div class="app" id="app">
<!-- 页面头部 -->
<div class="top-header">
<span class="f-left"><i class="icon-back" onclick="history.go(-1)"></i></span>
<span class="center">传智健康</span>
<span class="f-right"><i class="icon-more"></i></span>
</div>
<!-- 页面内容 -->
<div class="contentBox">
<div class="list-column1">
<ul class="list">
<#list setmealList as setmeal>
<li class="list-item">
<a class="link-page" href="setmeal_detail_${setmeal.id}.html">
<img class="img-object f-left"
src="http://rde7h6gzo.hn-bkt.clouddn.com/${setmeal.img}"
alt="">
<div class="item-body">
<h4 class="ellipsis item-title">${setmeal.name}</h4>
<p class="ellipsis-more item-desc">${setmeal.remark}</p>
<p class="item-keywords">
<span>
<#if setmeal.sex == '0'>
性别不限
<#else>
<#if setmeal.sex == '1'>
男
<#else>
女
</#if>
</#if>
</span>
<span>${setmeal.age}</span>
</p>
</div>
</a>
</li>
</#list>
</ul>
</div>
</div>
</div>
<!-- 页面 css js -->
<script src="../plugins/vue/vue.js"></script>
<script src="../plugins/vue/axios-0.18.0.js"></script>
</body>
mobile_setmeal_detail.ftl
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,user-scalable=no,minimal-ui">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../img/asset-favico.ico">
<title>预约详情</title>
<link rel="stylesheet" href="../css/page-health-orderDetail.css" />
<script src="../plugins/vue/vue.js"></script>
<script src="../plugins/vue/axios-0.18.0.js"></script>
<script src="../plugins/healthmobile.js"></script>
</head>
<body data-spy="scroll" data-target="#myNavbar" data-offset="150">
<div id="app" class="app">
<!-- 页面头部 -->
<div class="top-header">
<span class="f-left"><i class="icon-back" onclick="history.go(-1)"></i></span>
<span class="center">传智健康</span>
<span class="f-right"><i class="icon-more"></i></span>
</div>
<!-- 页面内容 -->
<div class="contentBox">
<div class="card">
<div class="project-img">
<img src="http://rde7h6gzo.hn-bkt.clouddn.com/${setmeal.img}"
width="100%" height="100%" />
</div>
<div class="project-text">
<h4 class="tit">${setmeal.name}</h4>
<p class="subtit">${setmeal.remark}</p>
<p class="keywords">
<span>
<#if setmeal.sex == '0'>
性别不限
<#else>
<#if setmeal.sex == '1'>
男
<#else>
女
</#if>
</#if>
</span>
<span>${setmeal.age}</span>
</p>
</div>
</div>
<div class="table-listbox">
<div class="box-title">
<i class="icon-zhen"><span class="path1"></span><span class="path2"></span></i>
<span>套餐详情</span>
</div>
<div class="box-table">
<div class="table-title">
<div class="tit-item flex2">项目名称</div>
<div class="tit-item flex3">项目内容</div>
<div class="tit-item flex3">项目解读</div>
</div>
<div class="table-content">
<ul class="table-list">
<#list setmeal.checkGroups as checkgroup>
<li class="table-item">
<div class="item flex2">${checkgroup.name}</div>
<div class="item flex3">
<#list checkgroup.checkItems as checkitem>
<label>
${checkitem.name}
</label>
</#list>
</div>
<div class="item flex3">${checkgroup.remark}</div>
</li>
</#list>
</ul>
</div>
<div class="box-button">
<a @click="toOrderInfo()" class="order-btn">立即预约</a>
</div>
</div>
</div>
</div>
</div>
<script>
var vue = new Vue({
el:'#app',
methods:{
toOrderInfo(){
window.location.href = "orderInfo.html?id=${setmeal.id}";
}
}
});
</script>
</body>
SetMealController
package com.shryu.controller;
import com.shryu.constant.MessageConstant;
import com.shryu.constant.RedisConstant;
import com.shryu.entity.PageResult;
import com.shryu.entity.QueryPageBean;
import com.shryu.entity.Result;
import com.shryu.pojo.Setmeal;
import com.shryu.service.ISetMealService;
import com.shryu.utils.QiniuUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import redis.clients.jedis.JedisPool;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
/**
* 体检套餐管理
*/
@RestController
@RequestMapping("/setMeal")
public class SetMealController {
@Autowired
private JedisPool jedisPool;
@Autowired
private ISetMealService setMealService;
@PostMapping("/upload")
public Result upload(@RequestParam("imgFile") MultipartFile imgFile){
System.out.println(imgFile);
String originalFilename = imgFile.getOriginalFilename(); //原始文件名:03a36073-a140-4942-9b9b-712cecb144901.jpg
int index = originalFilename.lastIndexOf(".");
String extention = originalFilename.substring(index); //.jpg
String fileName = UUID.randomUUID().toString() + extention; //FuM1Sa5TtL_ekLsdkYWcf5pyjKGu.jpg
try {
// 将文件上传到七牛云服务器
QiniuUtils.upload2Qiniu(imgFile.getBytes(),fileName);
jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES,fileName);
} catch (IOException e) {
e.printStackTrace();
return new Result(false, MessageConstant.PIC_UPLOAD_FAIL);
}
return new Result(true, MessageConstant.PIC_UPLOAD_SUCCESS,fileName);
}
// 新增套餐
@PostMapping("/add")
public Result add(@RequestBody Setmeal setmeal,Integer[] checkgroupIds) {
try {
setMealService.add(setmeal,checkgroupIds);
} catch (Exception e) {
e.printStackTrace();
return new Result(false,MessageConstant.ADD_SETMEAL_FAIL);
}
return new Result(true,MessageConstant.ADD_SETMEAL_SUCCESS);
}
// 分页查询
@PostMapping("/findPage")
public PageResult findPage(@RequestBody QueryPageBean queryPageBean){
return setMealService.pageQuery(queryPageBean);
}
// 查询所有套餐
@PostMapping("/getAllSetMeal")
public Result getAllSetMeal(){
try {
List<Setmeal> list = setMealService.findAll();
return new Result(true,MessageConstant.GET_SETMEAL_LIST_FAIL,list);
} catch (Exception e) {
e.printStackTrace();
return new Result(false,MessageConstant.GET_SETMEAL_LIST_FAIL);
}
}
// 根据套餐ID查询套餐详细信息(包括套餐基本信息、套餐包含的检查组、检查组包含的检查项)
@PostMapping("/findById")
public Result findById(int id){
try {
Setmeal setmeal = setMealService.findById(id);
return new Result(true,MessageConstant.QUERY_SETMEAL_FAIL,setmeal);
} catch (Exception e) {
e.printStackTrace();
return new Result(false,MessageConstant.QUERY_SETMEAL_SUCCESS);
}
}
}
ISetMealService
package com.shryu.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.shryu.entity.PageResult;
import com.shryu.entity.QueryPageBean;
import com.shryu.pojo.Setmeal;
import java.util.List;
public interface ISetMealService extends IService<Setmeal> {
void add(Setmeal setmeal,Integer[] checkgroupIds);
PageResult pageQuery(QueryPageBean queryPageBean);
List<Setmeal> findAll();
Setmeal findById(int id);
}
SetMealServiceImpl
package com.shryu.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.shryu.constant.RedisConstant;
import com.shryu.entity.PageResult;
import com.shryu.entity.QueryPageBean;
import com.shryu.mapper.SetMealMapper;
import com.shryu.pojo.Setmeal;
import com.shryu.service.ISetMealService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import redis.clients.jedis.JedisPool;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 体检套餐服务
*/
@Service
public class SetMealServiceImpl extends ServiceImpl<SetMealMapper, Setmeal> implements ISetMealService {
@Autowired
private JedisPool jedisPool;
@Autowired
private SetMealMapper setMealMapper;
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
@Value("${out_put_path}")
private String outPutPath; // 从属性文件中读取生成的html对应的目录
// 新增套餐信息 同时需要关联检查组
@Override
public void add(Setmeal setmeal, Integer[] checkgroupIds) {
setMealMapper.add(setmeal);
Integer setmealId = setmeal.getId();
this.setSetMealAndCheckGroup(setmealId,checkgroupIds);
// 将图片名称保存到Redis集合中
String fileName = setmeal.getImg();
jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES,fileName);
// 当添加套餐后需要重新生成静态页面(套餐列表页面、套餐详情页面)
generateMobileStaticHtml();
}
// 生成当前方法所需的静态页面
public void generateMobileStaticHtml(){
// 在生成静态页面之前需要查询数据
List<Setmeal> list = setMealMapper.findAll();
// 需要生成套餐列表静态页面
generateMobileSetMealListHtml(list);
// 需要生成套餐详情静态页面
generateMobileSetMealDetailHtml(list);
}
// 生成套餐列表静态页面
public void generateMobileSetMealListHtml(List<Setmeal> list){
Map map = new HashMap();
// 为模板提供数据 用于生成静态页面
map.put("setmealList",list);
generateHtml("mobile_setmeal.ftl","m_setmeal.html",map);
}
// 生成套餐详情静态页面(可能有多个)
public void generateMobileSetMealDetailHtml(List<Setmeal> list){
for (Setmeal setmeal : list) {
Map map = new HashMap();
map.put("setmeal",setMealMapper.findById(setmeal.getId()));
generateHtml("mobile_setmeal_detail.ftl","setmeal_detail_"+ setmeal.getId()+ ".html",map);
}
}
// 通用方法:用于生成静态页面
public void generateHtml(String templateName, String htmlPageName, Map map){
// 获得配置对象
Configuration configuration = freeMarkerConfigurer.getConfiguration();
Writer out = null;
try {
Template template = configuration.getTemplate(templateName);
// 构造输出流
out = new FileWriter(new File(outPutPath + "/" + htmlPageName));
// 输出文件
template.process(map,out);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public PageResult pageQuery(QueryPageBean queryPageBean) {
Integer currentPage = queryPageBean.getCurrentPage();
Integer pageSize = queryPageBean.getPageSize();
String queryString = queryPageBean.getQueryString();
PageHelper.startPage(currentPage,pageSize);
Page<Setmeal> page = setMealMapper.findByCondition(queryString);
return new PageResult(page.getTotal(),page.getResult());
}
@Override
public List<Setmeal> findAll() {
return setMealMapper.findAll();
}
// 根据套餐ID查询套餐详细信息(包括套餐基本信息、套餐包含的检查组、检查组包含的检查项)
@Override
public Setmeal findById(int id) {
return setMealMapper.findById(id);
}
// 设置套餐和检查组多对多关系 操作 t_setmeal_checkgroup
public void setSetMealAndCheckGroup(Integer setmealId,Integer[] checkgroupIds){
if (checkgroupIds != null && checkgroupIds.length > 0){
for (Integer checkgroupId : checkgroupIds) {
Map<String,Integer> map = new HashMap<>();
map.put("setmealId",setmealId);
map.put("checkgroupId",checkgroupId);
setMealMapper.setSetMealAndCheckGroup(map);
}
}
}
}
SetMealMapper
package com.shryu.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.github.pagehelper.Page;
import com.shryu.pojo.Setmeal;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
@Mapper
public interface SetMealMapper extends BaseMapper<Setmeal> {
void add(Setmeal setmeal);
void setSetMealAndCheckGroup(Map map);
Page<Setmeal> findByCondition(String queryString);
List<Setmeal> findAll();
Setmeal findById(int id);
}
SetMealMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.shryu.mapper.SetMealMapper">
<resultMap id="baseResultMap" type="com.shryu.pojo.Setmeal">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="code" property="code"/>
<result column="helpCode" property="helpCode"/>
<result column="sex" property="sex"/>
<result column="age" property="age"/>
<result column="price" property="price"/>
<result column="remark" property="remark"/>
<result column="attention" property="attention"/>
<result column="img" property="img"/>
</resultMap>
<resultMap id="findByIdResultMap" type="com.shryu.pojo.Setmeal" extends="baseResultMap">
<!--多对多映射-->
<collection
property="checkGroups"
ofType="com.shryu.pojo.CheckGroup"
select="com.shryu.mapper.CheckGroupMapper.findCheckGroupById"
column="id"
/>
</resultMap>
<!--插入套餐数据-->
<insert id="add">
/*通过mybatis框架提供的selectKey标签获得自增产生的ID值*/
<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
select LAST_INSERT_ID() /*获取刚刚添加的ID*/
</selectKey>
insert into t_setmeal(code,name,sex,helpCode,remark,attention,age,price,img)
values
(#{code},#{name},#{sex},#{helpCode},#{remark},#{attention},#{age},#{price},#{img})
</insert>
<!--设置套餐和检查组多对多关系-->
<insert id="setSetMealAndCheckGroup">
insert into t_setmeal_checkgroup(setmeal_id, checkgroup_id)
values
(#{setmealId},#{checkgroupId})
</insert>
<select id="findByCondition" resultType="com.shryu.pojo.Setmeal">
select * from t_setmeal
<if test="queryString != null and queryString != '' and queryString.length > 0">
where code = #{queryString} or name = #{queryString} or helpCode = #{queryString}
</if>
</select>
<select id="findAll" resultType="com.shryu.pojo.Setmeal">
select * from t_setmeal
</select>
<!--根据套餐ID查询套餐详细信息(包括套餐基本信息、套餐包含的检查组、检查组包含的检查项)-->
<select id="findById" parameterType="int" resultMap="findByIdResultMap">
select * from t_setmeal where id = #{id}
</select>
</mapper>