边学Springboot和thymeleaf 边做一个小项目遇到的问题记录

帮朋友写一个定制的后台管理和对外开放的API接口的项目,因为在之前的工作中没有使用到Spring boot等对我来说比较新的框架知识,为了学习,就边学边做,过程中肯定遇到了一些小问题,不过还是提前很多天完成了,然后在这里记录一下遇到的那些问题,以及怎么解决的,如果同行有更好的解决办法,请多指教。
我这里采用的框架是Springboot+mysql+mybatis+thymeleaf+bootstrap+maven的框架,因为是小项目,因此web后台和接口API没有独立开,直接在一个工程里面完成的。下面是整个工程的结构:

在这里插入图片描述

最开始是直接用idea给的Spring initlializr创建的Springboot web工程,并勾上mysql和mybatis需要的starter,过程选择自己的jdk版本,输入工程名称,直接next到最后就可以了,非常方便。

在做这个项目时没有分那么多层,mapper接口文件和SQL没有分开,也就是没有使用xxxMapper.xml文件来写SQL,直接使用的mybatis的@select,@Param等注解,遇到过参数没传进去报错的情况,这里就需要把单个的参数前加@Param(“xxx”)注解来指明才是是谁。当然,这里不只有@Select这个注解,还有@Insert、@Delete等,我就不多说了。
/**
 * @author Joey Zeng
 * @version 1.0.0, 2018-12-20
 */
@Component(value = "configMapper")
public interface ConfigMapper {
  @Select("select * from config where type=#{type} and status=0")
  public List<Config> selectConfig(@Param("type") Integer type);
}
为了工程能扫描到mapper,需要在工程的启动类上加上mapper的路径的注解@MapperScan(“cn.zyj.platform.mapper”),这样的话就不需要像以前那样在每个mapper类上写@Mapper注解了,省了很多事。
@MapperScan("cn.zyj.platform.mapper")
@SpringBootApplication
public class PlatformApplication {
  public static void main(String[] args) {
    SpringApplication.run(PlatformApplication.class, args);
  }
}

在写列表带条件查询的时候,SQL需要动态加入查询条件,需要用到if或者when,如下:

@Select("<script> select * from table_weibo where 1=1 and del_or_not=0"
    + "<if test='unBunned != 0'> and status !=1 and used=1 </if>"
    + " <when test='day!=0 and day!=16'> and TO_DAYS(now())-TO_DAYS(createTime) = ${day} </when>"
    + " <when test='day!=0 and day==16'> and TO_DAYS(now())-TO_DAYS(createTime) >=${day} </when>"
    + " order by createTime asc </script>")
  public List<Weibo> selectWeiboLists(@Param("day")Integer day,@Param("unBunned")Integer unBunned);
一般web后台的列表都需要分页,我这里用的是PageHelper来做的,一开始是在web用js来做的分页,需要一次把数据全部查出来,不过数据量很大的情况,就影响了首次加载的体验了,然后没考虑就用了PageHelper。

首先引入依赖:

<!-- mybatis分页功能 -->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>4.1.6</version>
    </dependency>

这里需要自定义Configuration。

/**
 * TODO
 *  mybatis 分页帮助类配置
 * @author Joey Zeng
 * @version 1.0.0, 2018-12-24
 */
@Configuration
public class MybatisPageHelperConfig {
  @Bean( name = "pageHelper" )
  public PageHelper pageHelper() {
    PageHelper pageHelper = new PageHelper();
    //添加配置,也可以指定文件路径
    Properties p = new Properties();
    p.setProperty("helperDialect", "mysql");
    p.setProperty("reasonable", "true");
    p.setProperty("supportMethodsArguments", "true");
    p.setProperty("params", "count=countSql");
    p.setProperty("autoRuntimeDialect", "true");
    pageHelper.setProperties(p);
    return pageHelper;
  }
}

这里配置自定义的configuration类需要加@Configuration注解和@Bean注解,不然不会生效。

PageHelper的使用,controller 如下:
@Controller
@RequestMapping("/ad")
public class AdvertiseManageController {
  Logger logger = LoggerFactory.getLogger(getClass());

  @Autowired
  AdvertiseService advertiseService;

  @RequestMapping("/list")
  public String weiboLists(Map<String, Object> map, @RequestParam(defaultValue = "1") Integer pageNum,
    @RequestParam(defaultValue = "14") Integer pageSize) {
    PageHelper.startPage(pageNum, pageSize);
    List<Advertise> advLists = advertiseService.getAdvertiseLists();
    PageInfo pageInfo = new PageInfo<>(advLists, pageSize);
    map.put("page",pageInfo);
    return "ad_list";
  }
}
使用了thymeleaf模版引擎:

首先依赖引入,或者在创建工程时直接勾上:

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

页面语法:

<!--分页-->
  <div class="row">
     <div class="col-sm-5" style="margin-top:7px;">
        <div class="dataTables_info" id="datatable_info" style="width: 80%;" role="status" aria-live="polite">
            显示 <span th:text="${page.getStartRow()}"></span>
            到 <span th:text="${page.getEndRow()}"></span> 
            总共 <span th:text="${page.getTotal()}"></span> 条 &nbsp; 
	    	 当前第:&nbsp;<span th:text="${page.getPageNum()}"></span>&nbsp;页,
	    	 总共&nbsp;<span th:text="${page.getPages()}"></span>&nbsp;页
        </div>
     </div>
     <div class="col-sm-7">
        <div class="dataTables_paginate paging_simple_numbers" id="datatable_paginate">
           <ul class="pagination" style="margin: 2px 0;">
               <li class="paginate_button previous" id="datatable_previous">
                  <a href="#" aria-controls="datatable" data-dt-idx="0" tabindex="0" th:if="${not page.isIsFirstPage()}" th:href="@{${'/ad/list'} (pageNum=${page.getPrePage()},pageSize=${page.getPageSize()})}">上一页</a>
                  <a href="#" aria-controls="datatable" data-dt-idx="0" tabindex="0" th:if="${page.isIsFirstPage()}" th:href="'javascript:void(0);'">上一页</a>
               </li>
               <li class="paginate_button next" id="datatable_next">
                  <a href="#" aria-controls="datatable" data-dt-idx="8" tabindex="0" th:if="${not page.isIsLastPage()}" th:href="@{${'/ad/list'}(pageNum=${page.getNextPage()},pageSize=${page.getPageSize()})}">下一页</a>
                  <a href="#" aria-controls="datatable" data-dt-idx="8" tabindex="0" th:if="${page.isIsLastPage()}"  th:href="'javascript:void(0);'">下一页</a>
               </li>
            </ul>
        </div>
    </div>
 </div>
<!--分页结束-->
页面效果如图:

在这里插入图片描述


这里总结一些页面中thymeleaf的一些使用语法:

首先得在页面引入thymeleaf,在html标签中加入:

<html lang="en" xmlns:th="http://www.thymeleaf.org">
  • 普通的获取值:
 <input type="hidden" id="pageSize" th:value="${page.getPageSize()}">`
  • href中跳转controller地址:
th:href="@{${'/xxx/xxx'}(pageNum=${page.getPrePage()},pageSize=${page.getPageSize()})}"
  • 标签里面调用js的function并传参数:
<a th:onclick="edit_ad([[${adv.id}]],[[${adv.detail}]],[[${adv.phoneMark}]],[[${adv.remarks}]]);">
   <i class="fa fa-pencil"></i> 编辑 
</a>
  • 判断boolean类型的值:
<a href="#" h:if="${not page.isIsFirstPage()}" th:href="@{${'/xxx/xxx'}(pageNum=${page.getPrePage()},pageSize=${page.getPageSize()})}">上一页</a>
<a th:if="${page.isIsFirstPage()}" th:href="'javascript:void(0);'">上一页</a>
  • 遍历数据:
<tr th:if="${page!=null}" th:each="aaa,aaaStatu:${page.getList()}">
    <td th:text="${aaaStatu.index+1}"></td>
    <td th:text="${aaa.name1}"></td>
    <td th:text="${aaa.name2}"></td>
    <td th:if="${aaa.name3==0}" th:text="未下载"></td>
    <td th:if="${aaa.name3==1}" th:text="已下载"></td>
    <td th:text="${#dates.format(aaa.createTime,'yyyy-MM-dd HH:mm:ss')}"></td>
    <td th:text="${aaa.name5}"></td>
</tr>
  • 格式化时间:
<td th:text="${#dates.format(aaa.createTime,'yyyy-MM-dd HH:mm:ss')}"></td>
  • 引用js/css:
<script th:src="@{/static/js/xxx/xxx.js}"></script>
<link th:href="@{/static/css/xxx.css}" rel="stylesheet">
  • include公共页面:
<div th:include="common::commonFooter"></div>

这其中common是提取的公共页面,commonFooter指的是给公共部分命的名:
在这里插入图片描述


以上这是比较简单的分页操作,没有条件查询,因此很容易实现,业务需求也没有条件查询,如果需要加入条件查询不知道有没有很好的解决办法?

虽然业务上没有条件查询,但是我用ajax来做了带条件查询动态生成的table行数据的效果,包括上下页都是js写的,不然条件参数不好带过去。如果有更好的办法就很好了。

然后在做ajax请求获取数据时就遇到了问题,json数据返回遇到问题,看了一下报错,应该是拦截器或者mvc配置的地方有问题,然后查看对应的地方,发现mvc继承的WebMvcConfigurationSupport,里面重写的configureMessageConverters方法里面确实只配置了对String相关的,因为我在写接口是接口返回中文时出现乱码,就在这儿设置了UTF-8编码,以及在aplication.properties里面配置了编码格式:
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8
因此,为了解决在我自己的WebMvcConfiguration的配置时,我没有继承WebMvcConfigurationSupport,而是实现了他父类WebMvcConfigurer,实现了里面configureMessageConverters接口,添加了json相关的配置:
/**
 * webmvc 配置类
 * @author Joey Zeng
 * @version 1.0.0, 2018-12-22
 */
@Configuration
public class MyWebMvcConfigurerAdapter implements WebMvcConfigurer {
  
//  继承WebMvcConfigurationSupport时为了注入自己的配置
//  @Bean
//  public HttpMessageConverter<String> responseBodyConverter() {
//    StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
//    return converter;
//  }

  /**
   * 配置接口中文乱码问题,以及ajax返回json数据拦截问题
   * @param converters
   */
  @Override
  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
    MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
    converters.add(converter);
    converters.add(mappingJackson2HttpMessageConverter);
  }

  @Override
  public void configureContentNegotiation(
    ContentNegotiationConfigurer configurer) {
    configurer.favorPathExtension(false);
  }
  /**
   * 配置静态资源的访问
   * @param registry
   */
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX+"/static/");
  }
  /**
   * 配置拦截规则
   * @param registry
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**") //用于添加拦截规则
      .excludePathPatterns("/login") // 用于开放登录页
      .excludePathPatterns("/index") // 用于排除拦截登录请求
      .excludePathPatterns("/static/**"); // 用于排除拦截静态资源
  }
}

然后这个问题就这样解决了,当然,得注意controller层,不管是接口返回数据还是ajax请求返回数据,都要加@ResponseBody注解。

另外在做导出数据功能时,当时遇到点击导出按钮并带上分页参数,没反应的情况,按钮是写的a标签,然后这里需要用到location.href :
location.href=exportExcelUrl+"?"+"pageNum="+pageNum+"&pageSize="+pageSize+"&day="+day+"&unbanned="+unbanned;

这个项目就到此为止了,希望各位大牛多提提意见。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值