Spring Boot系列四 与FreeMarker集成

Spring Boot 与FreeMarker集成

目录

  1. FreeMarker介绍
  2. Spring Boot与FreeMarker集成

运行环境:JDK 8,Maven 3.0+

技术栈:SpringBoot 2.5+ ,FreeMarker

FreeMarker 介绍

FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 是一个Java类库。

FreeMarker 被设计用来生成 HTML Web 页面,特别是基于 MVC 模式的应用程序,将视图从业务逻辑中抽离处理,业务中不再包括视图的展示,而是将视图交给 FreeMarker 来输出。虽然 FreeMarker 具有一些编程的能力,但通常由 Java 程序准备要显示的数据,由 FreeMarker 生成页面,通过模板显示准备的数据(如下图)。

在这里插入图片描述

FreeMarker不是一个Web应用框架,而适合作为Web应用框架一个组件。

FreeMarker与容器无关,因为它并不知道HTTP或Servlet。FreeMarker同样可以应用于非Web应用程序环境。

FreeMarker更适合作为Model2框架(如SpringMVC)的视图组件,你也可以在模板中使用JSP标记库。

Spring Boot与FreeMarker集成

数据库及表创建

  • 数据库创建:

    create database sopbase;

  • 表创建:

    create table sys_user
    (
    user_id bigint auto_increment
    primary key
    ,
    username varchar(50) not null comment ‘用户名’,
    password varchar(100) null comment ‘密码’,
    salt varchar(20) null comment ‘盐’,
    email varchar(100) null comment ‘邮箱’,
    mobile varchar(100) null comment ‘手机号’,
    status tinyint null comment ‘状态 0:禁用 1:正常’,
    dept_id bigint null comment ‘部门ID’,
    create_time datetime null comment ‘创建时间’,
    constraint username
    unique (username)
    )
    comment ‘系统用户’ charset = utf8mb4;

项目工程结构及源码介绍

结合前一章节基础上,来增加freemarker组件以及Web开发

项目工程结构

在这里插入图片描述

核心源码介绍
  1. controller 层

    @Controller
    public class UserFreeMarkerController {
    @Autowired
    private UserService userService;

    @RequestMapping(“{url}.html”)
    public String module( @PathVariable(“url”) String url){
    *//返回路径前面

    • return url;
      }

    */**
    * 保存
    */

    • @PostMapping(“/save”)
      public String save(@ModelAttribute(“form”) User user){
      userService.stroe(user);
      return “success”;
      }

    @GetMapping(“/list”)
    @ResponseBody
    public R list(@RequestParam Map<String, Object> params){
    PageUtils page = userService.queryPage(params);

    return R.ok().put(“page”, page);
    }

    }

  2. dao – 数据操作层 DAO

    @Mapper
    *//表明这是一个Mapper,也可以在启动类上加上包扫描
    //Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
    *public interface UserMapper extends BaseMapper<User> {

    }

  3. entity – 实体类

    @Data
    @TableName(value = “sys_user”)
    @ApiModel(description = “用户信息”)
    public class User implements Serializable {
    private static final long serialVersionUID = -5644799954031156649L;

    *//value与数据库主键列名一致,若实体类属性名与表主键列名一致可省略value

    • @TableId(value = “user_id”, type = IdType.AUTO)*//指定自增策略
    • @ApiModelProperty(value = “用户ID”,required=true)
      private Long userId;
      */**
      * 用户名
      */
    • @ApiModelProperty(value = “用户名”,required=true)
      private String username;
      */**
      * 密码
      */
    • @ApiModelProperty(value = “用户密码”,required=true)
      private String password;
      */**
      * 盐
      */
    • private String salt;
      */**
      * 邮箱
      */
    • @ApiModelProperty(value = “用户邮箱”,required=true)
      private String email;
      */**
      * 手机号
      */
    • private String mobile;
      */**
      * 状态 0:禁用 1:正常
      */
    • private Integer status;
      */**
      * 部门ID
      */
    • private Long deptId;

    */**
    * 部门名称
    */

    • @TableField(exist=false)
      private String deptName;

    */**
    * 角色ID列表
    */

    • @TableField(exist=false)
      private List<Long> roleIdList;

    */**
    * 创建时间
    */

    • @TableField(fill= FieldFill.INSERT_UPDATE)
      private Date createTime;

    }

  4. service – 业务逻辑层

    接口类:

    public interface UserService extends IService<User> {
    /**
    * 分页查询
    *
    **@param params
    ** * **@return
    ** **/

    • PageUtils queryPage(Map<String, Object> params);

    /**
    * 根据姓名查询
    *
    **@param name
    ** * **@return
    ** **/

    • User queryByName(String name);

    boolean stroe(User user);

    void update(User user);

    User getUserById(Long userId);

    }

    实现类:

    @Service(“userService”)
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
    String name = (String)params.get(“username”);
    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
    userQueryWrapper.like(StringUtils.isNotEmpty(name),“username”,name);
    Query<User> query = new Query<>();
    IPage<User> page= this.page(query.getPage(params),userQueryWrapper);
    return new PageUtils(page);
    }

    @Override
    public User queryByName(String name) {
    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
    userQueryWrapper.eq(“username”,name);
    return this.getOne(userQueryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean stroe(User user) {
    String salt = RandomStringUtils.randomAlphanumeric(20);
    String pwd = user.getPassword()+salt;
    user.setSalt(salt);
    user.setPassword(DigestUtils.md5Hex(pwd));
    this.save(user);
    return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(User user) {
    if(org.apache.commons.lang.StringUtils.isBlank(user.getPassword())){
    user.setPassword(null);
    }else{
    String salt = RandomStringUtils.randomAlphanumeric(20);
    String pwd = user.getPassword()+salt;
    user.setSalt(salt);
    user.setPassword(DigestUtils.md5Hex(pwd));
    }
    this.updateById(user);

    }

    @Override
    public User getUserById(Long userId) {
    User user = this.getById(userId);
    return user;
    }
    }

  5. WebConfig –配置

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    //静态资源请求
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler(“/static/**”)
    .addResourceLocations(“classpath:/static/”);
    }

    }

  6. Application – 应用启动类

    /**
    * 启动类
    *
    *
    @author *lxj
    */
    *@SpringBootApplication
    public class LearnFreeMarkerApplication {
    public static void main(String[] args) {
    SpringApplication.run(LearnFreeMarkerApplication.class, args);
    }
    }

  7. Mapper配置

    *<?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.learn.springboot.dao.UserMapper”>

    *<!-- 可根据自己的需求,是否要使用 -->

    • <resultMap type=“com.learn.springboot.entity.User” id=“userMap”>
      <result property=“userId” column=“user_id”/>
      <result property=“username” column=“username”/>
      <result property=“password” column=“password”/>
      <result property=“salt” column=“salt”/>
      <result property=“email” column=“email”/>
      <result property=“mobile” column=“mobile”/>
      <result property=“status” column=“status”/>
      <result property=“deptId” column=“dept_id”/>
      <result property=“createTime” column=“create_time”/>
      </resultMap>

    </mapper>

  8. application.yml – 应用配置文件,应用启动会自动读取配置

    server:
    port: 80
    servlet:
    context-path: /

    tomcat:
    *# tomcat的URI编码

    • uri-encoding: UTF-8
      *# tomcat最大线程数,默认为200
    • max-threads: 800
      *# Tomcat启动初始化的线程数,默认值25
    • min-spare-threads: 30

    spring:
    datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: sopbase
    password: sopbase
    url: jdbc:mysql://localhost:3306/sopbase?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    initial-size: 10 *#连接池初始大小

    • max-active: 100 *#连接池中最大的活跃连接数
    • min-idle: 10 *#连接池中最小的活跃连接数
    • max-wait: 60000 *#配置获取连接等待超时的时间
    • pool-prepared-statements: true *#打开PSCache,并且指定每个连接上PSCache的大小
    • max-pool-prepared-statement-per-connection-size: 20
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      *#Oracle需要打开注释
      #validation-query: SELECT 1 FROM DUAL
    • test-while-idle: true *#是否在连接空闲一段时间后检测其可用性
    • test-on-borrow: false *#是否在获得连接后检测其可用性
    • test-on-return: false *#是否在连接放回连接池后检测其可用性
    • stat-view-servlet:
      enabled: true
      url-pattern
      : /druid/*
      *#login-username: admin
      #login-password: admin
    • filter:
      stat:
      log-slow-sql: true
      slow-sql-millis
      : 1000
      merge-sql: false
      wall
      :
      config:
      multi-statement-allow: **true

    ** *# freemarker模板引擎

    • freemarker:
      allow-request-override: true
      allow-session-override
      : true
      cache
      : false
      check-template-location
      : true
      charset
      : UTF-8
      content-type: text/html;
      expose-request-attributes: true
      expose-session-attributes
      : true
      expose-spring-macro-helpers
      : true
      template-loader-path
      : classpath:/templates/
      prefix:
      suffix: .html
      request-context-attribute: request
      settings:
      template_update_delay: 0
      url_escaping_charset: UTF-8
      locale: UTF-8
      datetime_format: yyyy-MM-dd HH:mm:ss
      date_format: yyyy-MM-dd
      time_format: HH:mm:ss
      template_exception_handler: html_debug
      *# 数字格式化,无小数点
    • number_format: **‘0.#’
      ** *# 设置freemarker标签 0,1,2 0=自动识别,默认1
    • tag_syntax: ‘auto_detect’
      resources
      :
      static-locations: classpath:/templates/

    *#mybatis
    *mybatis-plus:
    mapper-locations: classpath*:/mapper/**/*.xml
    *#实体扫描,多个package用逗号或者分号分隔 com.example.*.entity

    • typeAliasesPackage: com.learn.springboot.entity
      global-config:
      *#数据库相关配置
    • db-config:
      *#主键类型 AUTO:“数据库ID自增”, INPUT:“用户输入ID”, ID_WORKER:“全局唯一ID (数字类型唯一ID)”, UUID:“全局唯一ID UUID”;
    • id-type: *AUTO
    • logic-delete-value: -1
      logic-not-delete-value: 0
      banner: **false
      ** *#原生配置
    • configuration:
      *#开启sql日志
      #log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    • log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
      *#log-impl: org.apache.ibatis.logging.log4j2.Log4j2Impl
      # 该配置就是将带有下划线的表字段映射为驼峰格式的实体类属性
    • map-underscore-to-camel-case: true
      cache-enabled
      : false
      call-setters-on-nulls
      : true
      jdbc-type-for-null
      : null
  9. 页面代码

    <!DOCTYPE html>
    <html>
    <head>
    <title>用户信息</title>
    <meta charset=“UTF-8”>
    <meta http-equiv=“X-UA-Compatible” content=“IE=edge”>
    <meta content=“width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no” name=“viewport”>
    <link rel=“stylesheet” type=“text/css” href=“${request.contextPath}/static/css/bootstrap.min.css”>
    <link rel=“stylesheet” type=“text/css” href=“${request.contextPath}/static/plugins/jqgrid/ui.jqgrid-bootstrap.css”>
    <link rel=“stylesheet” href=“${request.contextPath}/static/css/font-awesome.min.css”>
    <script type=“text/javascript” src=“${request.contextPath}/static/js/jquery.min.js”></script>
    <script type=“text/javascript” src=“${request.contextPath}/static/js/bootstrap.min.js”></script>
    <script type=“text/javascript” src=“${request.contextPath}/static/plugins/jqgrid/grid.locale-cn.js”></script>
    <script type=“text/javascript” src=“${request.contextPath}/static/plugins/jqgrid/jquery.jqGrid.min.js”></script>
    </head>
    <body>
    <div class=“container”>
    <div class=“row clearfix”>
    <div class=“grid-btn”>
    <div class=“col-sm-2”>
    <input type=“text” class=“form-control” id=“username” name=“username” @keyup.enter=“query” placeholder=“用户名”>
    </div>

    <a class=“btn btn-primary” οnclick=“query()>查询</a>
    <a class=“btn btn-primary” @click=“add”><i class=“fa fa-plus”></i>&nbsp;新增</a>
    <a class=“btn btn-primary” @click=“update”><i class=“fa fa-pencil-square-o”></i>
    &nbsp;修改</a>
    <a class=“btn btn-primary” @click=“del”><i class=“fa fa-trash-o”></i>
    &nbsp;删除</a>
    </div>
    <table id=“jqGrid”></table>
    <div id=“jqGridPager”></div>
    </div>
    </div>
    </body>
    </html>
    <script type=“text/javascript”>
    $(function () {
    $(
    “#jqGrid”
    ).jqGrid({
    url: ‘/list’,
    datatype: “json”,
    colModel: [
    { label: ‘用户ID’, name: ‘userId’, index: “user_id”, width: 45, key: true },
    { label: ‘用户名’, name: ‘username’, width: 75 },
    { label: ‘所属部门’, name: ‘deptName’, sortable: false, width: 75 },
    { label: ‘邮箱’, name: ‘email’, width: 90 },
    { label: ‘手机号’, name: ‘mobile’, width: 100 },
    { label: ‘状态’, name: ‘status’, width: 60, formatter: function(value, options, row){
    return value === 0 ?
    ‘<span class=“label label-danger”>禁用</span>’ :
    ‘<span class=“label label-success”>正常</span>’;
    }},
    { label: ‘创建时间’, name: ‘createTime’, index: “create_time”, width: 85}
    ],
    viewrecords: true,
    height: 385,
    rowNum: 10,
    rowList : [10,30,50],
    rownumbers: true,
    rownumWidth: 25,
    autowidth:true,
    multiselect: true,
    pager: “#jqGridPager”,
    jsonReader : {
    root: “page.list”,
    page: “page.currPage”,
    total: “page.totalPage”,
    records: “page.totalCount”
    ** },
    prmNames : {
    page:
    “page”,
    rows:
    “limit”**,
    order: **“order”
    ** },
    gridComplete:function(){
    *//隐藏grid底部滚动条

    • $(“#jqGrid”).closest(“.ui-jqgrid-bdiv”).css({ “overflow-x” : “hidden” });
      }
      });
      });

    function query(){
    var page = $(“#jqGrid”).jqGrid(‘getGridParam’,‘page’);

    $(“#jqGrid”).jqGrid(‘setGridParam’,{
    postData:{‘username’: $(“#username”).val()},
    page:page
    }).trigger(“reloadGrid”);
    };

    $(document).ready(function(){
    query();
    });

    *//jqGrid的配置信息

    • $.jgrid.defaults.width = 1000;
      $.jgrid.defaults.responsive = true;
      $.jgrid.defaults.styleUI = ‘Bootstrap’;
      </script>
项目配置说明
  1. 项目pom.xml添加freemarker依赖

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>

  2. application.yml数据源配置
    在这里插入图片描述

  3. application.yml中freemarker配置

    方式一:

@Configuration
public class FreemarkerConfig {

@Bean
public FreeMarkerConfigurer freeMarkerConfigurer(){
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath(“classpath:/templates”);

Map<String, Object> variables = new HashMap<>(1);
variables.put(“suffix”,“.html”);
configurer.setFreemarkerVariables(variables);

Properties settings = new Properties();
settings.setProperty(“default_encoding”, “utf-8”);
settings.setProperty(“number_format”, “0.##”);
configurer.setFreemarkerSettings(settings);
return configurer;
}

}

方式二:

在这里插入图片描述

工程演示
  1. 右键运行 Application 应用启动类的 main 函数,然后在浏览器访问:

http://127.0.0.1/userList.html

  1. 可以看到返回的结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kYH4XwVd-1677899618360)(media/c901241187cf594b6b6b615165954885.png)]

重点注意:

  1. 静态资源在工程的受限访问区域,需要现实WebMvcConfigurer接口,方向静态资源目录
  2. 配置的 Freemarker 文件配置路径下的各个 *.html 文件名一致。这样才会准确地把数据渲染到 html 文件里面进行展示。
  3. 用 Model 类,向 Model 加入数据,并指定在该数据在 Freemarker 取值指定的名称。

ettings.setProperty(“number_format”, “0.##”);
configurer.setFreemarkerSettings(settings);
return configurer;
}

}

方式二:

在这里插入图片描述

工程演示
  1. 右键运行 Application 应用启动类的 main 函数,然后在浏览器访问:

http://127.0.0.1/userList.html

  1. 可以看到返回的结果
    [外链图片转存中...(img-kYH4XwVd-1677899618360)]

重点注意:

  1. 静态资源在工程的受限访问区域,需要现实WebMvcConfigurer接口,方向静态资源目录
  2. 配置的 Freemarker 文件配置路径下的各个 *.html 文件名一致。这样才会准确地把数据渲染到 html 文件里面进行展示。
  3. 用 Model 类,向 Model 加入数据,并指定在该数据在 Freemarker 取值指定的名称。
  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值