SpringBoot 整合 Freemaker 配置

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>

5.生成页面展示

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KiriSoyer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值