Layui超链接分页的实现

后端数据回显查看之前的博文:Spring Boot之分页Layui的分页是JS动态生成的,这样搜索引擎抓取不到分页的数据,模拟抓取时,是一片空白,没有数据,传统的超链接分页则是可以抓取的,有利于SEO。下面我们就来实现一下超链接分页的laypage。

<div class="layui-box layui-laypage" th:with="maxButtons=10,floatButtons=5">
    <!-- 上一页 -->
    <th:block th:if="${articlePage.currentPage == 1}"><a class="layui-disabled">上一页</a></th:block>
    <th:block th:if="${articlePage.currentPage > 1}"><a th:href="@{'/blog/pages?page='+${articlePage.currentPage-1}}">上一页</a></th:block>

    <!-- 首页 -->
    <span th:if="${articlePage.currentPage == 1}" class="layui-laypage-curr"><em class="layui-laypage-em" style="background-color:#009688;"></em><em>1</em></span>
    <th:block th:if="${articlePage.currentPage > 1}"><a th:href="@{'/blog/pages?page=1'}">1</a></th:block>

    <!-- 总页数小于maxButtons时,全部显示 -->
    <th:block th:if="${articlePage.totalPage>=1 && articlePage.totalPage<=maxButtons}" th:each="i : ${#numbers.sequence(1,articlePage.totalPage-1)}">
        <span th:if="${articlePage.currentPage == i}"  class="layui-laypage-curr"><em class="layui-laypage-em" style="background-color:#009688;"></em><em th:text="${i}">页码</em></span>
        <th:block th:if="${articlePage.currentPage != i}"> <a th:href="@{'/blog/pages?page='+${i}}" th:text="${i}">页码</a></th:block>
    </th:block>

    <th:block th:if="${articlePage.totalPage > maxButtons}">
        <th:block th:if="${(articlePage.currentPage-(floatButtons/2)) <= 2}" th:each="i : ${#numbers.sequence(2,2+floatButtons-1)}">
            <span th:if="${articlePage.currentPage == i}"  class="layui-laypage-curr"><em class="layui-laypage-em" style="background-color:#009688;"></em><em th:text="${i}">页码</em></span>
            <th:block th:if="${articlePage.currentPage != i}"><a  th:href="@{'/blog/pages?page='+${i}}" th:text="${i}">页码</a></th:block>
        </th:block>
        <!-- ... -->
        <th:block th:if="${(articlePage.currentPage-(floatButtons/2))>2}"><a>...</a></th:block>

        <th:block th:if="${((articlePage.currentPage-(floatButtons/2))>2) && ((articlePage.currentPage+(floatButtons/2)-(floatButtons%2==0?1:0)) < (articlePage.totalPage-1))}"
                  th:each="i : ${#numbers.sequence(articlePage.currentPage-(floatButtons/2),articlePage.currentPage+(floatButtons/2)-(floatButtons%2==0?1:0))}">
            <span th:if="${articlePage.currentPage == i}"  class="layui-laypage-curr"><em class="layui-laypage-em" style="background-color:#009688;"></em><em th:text="${i}">页码</em></span>
            <th:block th:if="${articlePage.currentPage != i}"><a th:href="@{'/blog/pages?page='+${i}}" th:text="${i}">页码</a></th:block>
        </th:block>

        <!-- ... -->
        <th:block th:if="${(articlePage.currentPage+(floatButtons/2)-(floatButtons%2==0?1:0)) < (articlePage.totalPage-1)}"><a>...</a></th:block>
        <th:block th:if="${(articlePage.currentPage+(floatButtons/2)-(floatButtons%2==0?1:0)) >= (articlePage.totalPage-1)}" th:each="i : ${#numbers.sequence(articlePage.totalPage-floatButtons,articlePage.totalPage-1)}">
            <span th:if="${articlePage.currentPage == i}"  class="layui-laypage-curr"><em class="layui-laypage-em" style="background-color:#009688;"></em><em th:text="${i}">页码</em></span>
            <th:block th:if="${articlePage.currentPage != i}"><a th:href="@{'/blog/pages?page='+${i}}" th:text="${i}">页码</a></th:block>
        </th:block>
    </th:block>

    <!-- 最后一页 -->
    <span th:if="${articlePage.totalPage>1 && articlePage.currentPage == articlePage.totalPage}" class="layui-laypage-curr"><em class="layui-laypage-em" style="background-color:#009688;"></em><em th:text="${articlePage.totalPage}">页码</em></span>
    <th:block th:if="${articlePage.totalPage>1 && articlePage.currentPage != articlePage.totalPage}"><a th:href="@{'/blog/pages?page='+${articlePage.totalPage}}" th:text="${articlePage.totalPage}">页码</a></th:block>


    <!-- 下一页 -->
    <th:block th:if="${articlePage.currentPage >= articlePage.totalPage}"><a class="layui-disabled">下一页</a></th:block>
    <th:block th:if="${articlePage.currentPage < articlePage.totalPage}"><a th:href="@{'/blog/pages?page='+${articlePage.currentPage+1}}">下一页</a></th:block>

</div>

articlePage.currentPage : 当前页码,后台返回的参数

articlePage.totalPage:总页数,后台返回的参数

maxButtons:最小显示页码数,即总页数小于等于这个数,页码将会全部显示,不会出现省略号,本例中为10

floatButtons:最多展示页码数,即总页数大于maxButtons时,除首尾页码外,还需显示的页码数,本例为5
上一页、首页、最后一页、下一页均是固定页码数,代码易懂;总页数小于maxButtons时,页码全部显示,代码也很容易理解;下面主要说有省略号的情况。

最外层先判断页码总数大于最小显示页码数,即 articlePage.totalPage > maxButtons:

1. articlePage.currentPage-(floatButtons/2)) <= 2 :当前页减去最多展示页码数的一半小于等于2时,这时候,当前页连续的floatButtons个页码为前5(这里的floatButtons=5)项(除页码1外),此时在后面加上省略号即可。

2. articlePage.currentPage-(floatButtons/2))>2 :与1相反,此时会在页码1后有省略号页码,之后显示当前页连续的5个页码

3. ((articlePage.currentPage-(floatButtons/2))>2) && ((articlePage.currentPage+(floatButtons/2)-(floatButtons%2==0?1:0)) < (articlePage.totalPage-1)) :&&前的部分如情况2所讲,后半部分的意思是当前页加上它之后的两个页码(当前页为中间值,加上后2个一共是5个,即floatButtons),是否小于总页数减去1,如果小于还有省略号

4.紧接3后的省略号

5.与3相反,如果大于等于,则不需要末尾的省略号,当前页面连续5页都显示出来即可。上面就是个人的分析,如有不懂或错误请留言交流。

Layui 实现火车站点选择功能

先看效果:


为什么要用这种方式?

答:数据量太大,直接采用下拉框会加载缓慢,采用数据表格分页的方式能够很好的适应,个人借鉴,各位有好的方法也可以相互交流或者提出建议。

下面正式开始:

1.表结构和sql

sql文件:点击下载

2.实体类 -Station.java

import java.io.Serializable;

/**
 * 
 * @description ...
 * @author  wujianyu
 * @email wjy329@vip.qq.com
 * @date  2019年2月12日 下午4:48:33
 */
public class Station implements Serializable {
private static final long serialVersionUID = 1L;

/**主键**/
private Integer id;
/**站点名称**/
private String station;

/**
 * 设置:主键
 */
public void setId(Integer id) {
this.id = id;
}
/**
 * 获取:主键
 */
public Integer getId() {
return id;
}
/**
 * 设置:站点名称
 */
public void setStation(String station) {
this.station = station;
}
/**
 * 获取:站点名称
 */
public String getStation() {
return station;
}
}

3.Dao

StationDao.java:

public interface StationDao{
  List<Station>  queryPage(@Param(value="page") PageInfo page);
  
  Integer getAllCnt();

/**
 * @description ...
 * @author  wujianyu
 * @email wjy329@vip.qq.com
 * @date  2019年2月13日 上午11:09:23
 */
Integer getCntByName(String station);

/**
 * @description ...
 * @author  wujianyu
 * @email wjy329@vip.qq.com
 * @date  2019年2月13日 上午11:09:29
 */
List<Station> queryPageByName(@Param(value="page")PageInfo pageInfo,@Param(value="station")String station);
}

StationDao.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="xxx.StationDao">
<resultMap type="xxx.entity.Station" id="stationMap">
<result property="id" column="id" />
<result property="station" column="station" />
</resultMap>

<select id="getAllCnt" resultType="java.lang.Integer">
select count(id) from t_station
</select>

<select id="queryPage" parameterType="xxx.entity.PageInfo" resultMap="stationMap">
select
*
from t_station
order by id asc
<if test="page.limit != null">
<if test="page.offset != null">
limit ${page.offset}, ${page.limit}
</if>
<if test="page.offset == null">
limit ${limit}
</if>
</if>
</select>

<select id="getCntByName" resultType="java.lang.Integer">
    select count(id) from t_station where station LIKE #{station,jdbcType=VARCHAR}
  
</select>
  

  
<select id="queryPageByName"  parameterType="xxx.entity.PageInfo" resultMap="stationMap">
    select
*
from t_station 
where station LIKE #{station,jdbcType=VARCHAR}
    order by id asc
     <if test="page.limit != null">
      <if test="page.offset != null">
        limit ${page.offset}, ${page.limit}
      </if>
      <if test="page.offset == null">
        limit ${limit}
      </if>
    </if>
 
</select>
</mapper>

4.Service

StationService.java:

import com.alibaba.fastjson.JSONArray;

public interface StationService {

public List<Station> queryByPage(String station);

}

StationServiceImpl.java:

@Service("stationService")
@Transactional
public class StationServiceImpl implements StationService {
@Autowired
private StationDao stationDao;

@Override
public List<Station> queryByPage(String station) {
// 判断条数
Integer total = 0;
// 查询分页数据
List<Station> result = null;

if (!StringUtils.isEmpty(station)) {
station = "%" + station + "%";
total = this.stationDao.getCntByName(station);
result = this.stationDao.queryPageByName(SystemPageContext.getPageInfo(), station);
} else {
total = this.stationDao.getAllCnt();
result = this.stationDao.queryPage(SystemPageContext.getPageInfo());
}
// 设定总的数据量
SystemPageContext.setTotal(total);

return result;
}

}

5.Controller

StationController.java

/**
 * @description ...
 * @author wujianyu
 * @email wjy329@vip.qq.com
 * @date 2019年2月12日 下午4:37:56
 */
@Controller
@RequestMapping("/station")
public class StationController {
@Autowired
private StationService stationService;

/**
 * 
 * @description 跳转到站点选择界面
 * @author  wujianyu
 * @email wjy329@vip.qq.com
 * @date  2019年2月12日 下午4:39:01
 */
@RequestMapping("/list/{domId}")
public String list(Model model, @PathVariable("domId") String domId) {
model.addAttribute("domId", domId);
return "station/list.jsp";
}

@ResponseBody
@RequestMapping(value="/allStation",produces="application/json;charset=UTF-8")
public Map<String, Object> listData(String station){
//从数据库中获取到数据
List<Station> rs = this.stationService.queryByPage(station);
return WebUtils.getInstance().getLayuiPageResult(rs);
}

}

6.页面和js

list.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet"
href="${rc.contextPath}/statics/plugins/layui-v2.4.5/layui/css/layui.css"
media="all">
<script
src="${rc.contextPath}/statics/plugins/layui-v2.4.5/layui/layui.js"></script>
<title>Insert title here</title>
</head>
<body>
<input id="domId" type="hidden"
value="<c:out value="${domId}" escapeXml="true" />" />
<table class="layui-hide" id="station_list" lay-filter="station_list"></table>
<script type="text/html" id="toolbarDemo">
<div class="layui-inline">
             <div class="layui-btn-container">
                 <button class="layui-btn layui-btn-sm" lay-event="getCheckData">选择站点</button>
             </div>
        </div>
<div class="layui-inline">
    <div class="layui-input-inline">
    
<input type="text" value="" id="keyWords" placeholder="请输车站名查询" class="layui-input search_input" style="height:30px;">
    </div>
    <a class="layui-btn layui-btn-sm" lay-event="searchStation">查询</a>
</div>
<div class="layui-inline">
             <div class="layui-btn-container">
                 <button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="delSelect">删除已选站点</button>
             </div>
        </div>
    </script>
<script type="text/javascript" src="/page/station/js/list.js"></script>
</body>
</html>

list.js

layui.use(['form','table', 'laydate','jquery'], function () {
    var form = layui.form,
    
table = layui.table,
        layer = layui.layer,
        laydate = layui.laydate,
        $ = layui.jquery;
var domId = $('#domId').val();
    var stationTable = table.render({
     elem: '#station_list'
    ,url:'/station/allStation'
    ,toolbar: '#toolbarDemo'
    ,defaultToolbar: []
    ,id:'id'
    ,page: { //支持传入 laypage 组件的所有参数(某些参数除外,如:jump/elem) - 详见文档
        layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局
      //,curr: 5 //设定初始在第 5 页
      ,groups: 1 //只显示 1 个连续页码
      ,first: false //不显示首页
      ,last: false //不显示尾页
      
    },request: {
    
  pageName: 'page' //页码的参数名称,默认:page
         ,limitName: 'limit' //每页数据量的参数名,默认:limit
},
    response: {
    
  statusCode: 1 //成功的状态码,默认:0
    }      
    ,cols: [[
    
{type:'radio'}
      ,{field:'id', width:'10%', title: 'ID',hidden:true, sort: true}
      ,{field:'station', title: '车站名称'}
    ]]
  });
    
    //头工具栏事件
    table.on('toolbar(station_list)', function(obj){
      var checkStatus = table.checkStatus(obj.config.id); //获取选中行状态
      switch(obj.event){
        case 'getCheckData':
          var data = checkStatus.data;  //获取选中行数据
          var station = data[0].station;
          parent.$("#"+domId+"").val(station);
          //关闭当前的frame
  
  var index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引
  
  parent.layer.close(index); //再执行关闭   
        break;
        case 'searchStation':
        
var keywords = $("#keyWords").val();
    
    stationTable.reload(
    
    
{page: {
    
            curr: 1 //重新从第 1 页开始
    
        }
    
        ,url: '/station/allStation',
    
    
where: {station:keywords}}
    
   );
    break;
        case 'delSelect':
        
parent.$("#"+domId+"").val("");
    break;
      };
    });
    
});

上面就是完整的代码,其他页面中使用时,只需获取dom的点击事件,弹出layer(或者其他)指向/station/list 页面即可。

其他需要类似的功能也可以使用上述方法,仅仅是本人的实践记录,如有其它方法,欢迎交流。

Layui单选框赋值

这个赋值是从一个页面获取到数据,复制到另一个页面,常用于更新。

更新页面:

<div class="layui-form-item">
   <label class="layui-form-label">类型</label>
   <div class="layui-input-block">
      <input type="radio" name="type" value="0" title="菜单">
      <input type="radio" name="type" value="1" title="按钮">
   </div>
</div>

赋值的js:

var body = layer.getChildFrame('body', index);
body.find("input[name='type'][value='" + data.type +"']").prop('checked',true);
form.render();

FTP返回530错误(重置FTP用户密码)

最近做的上传文件到FTP服务器,发现返回了530错误,以前也没接触过,经过查找发现多半是用户名密码问题,然后登陆服务器对其重置了FTP密码,好使!

查看注册的FTP账号:

cat /etc/vsftpd/chroot_list

image.png

例如我的注册账号为ftpuser

然后重置密码,下面的ftpuser是我的用户名,换成自己的即可。

passwd ftpuser

image.png

即可。

wmanage-基于Spring Boot+MyBatis+Shiro+LayUI的后台管理系统

之前的 wAdmin-基于Spring Boot+MyBatis+Layui的后台管理系统  废弃,原因就是别人的东西改不来,都是bug,不如自己动手,哈哈哈。

经过一段时间的重构,终于可以用了,测试也没有bug,以后也会慢慢更新。

详见:Github

原系统里面树形菜单采用了jTree,整了半天也没明白,索性,自己研究了zTree,开始感觉很难,做了一段时间后,发现也就那么回事,洒洒水啦,哈哈哈。这给了我一点启发,只要学习,就会有收获。

关于shiro的之前也写了一些东西,但发现是有些错误的,随着现在学习的深入,之后会进行修改的,希望理解。毕竟是一只前进中的菜鸡。

不多说了,Go!

工具类中调用Service层

我们通常抽取很多共同的方法作为一个工具类,但是有的工具类,可能会用到Service层的方法来查找对象或者其他操作,工具类的方法是静态的,Service不能是静态,怎么办呢?下面是一种可行的办法:

直接看工具类:

/**
 * @description ...
 * @author  wujianyu
 * @email wjy329@vip.qq.com
 * @date  2019年1月18日 上午10:42:31
 */
package com.wjy329.utils;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.wjy329.service.WjyService;


@Component
public class WUtil {
	
	private static WUtil wUtil ;
	
	@Autowired
	private WjyService wjyService;
	
	@PostConstruct
	public void init() {
	    wUtil = this;
	}

    public static void function(){
      wUtil.wjyService.add();
    }

}

注意初始化时,加上  @PostConstruct  注解。这样就可以了。

zTree的使用-初始化、异步加载数据

zTree的官方网站:    http://www.treejs.cn/v3/main.php#_zTreeInfo

如何引入js和css,这里就不介绍了,直接看官方文档即可—zTree入门指南

在html中找到你要放置zTree的地方,id可变,class为ztree

<ul id="tree" class="ztree"></ul>
<script type="text/javascript">
    //加载资源树
    var t = $("#tree");
    var zNodes ;
     //zTree参数设置
    var setting = {
        treeId:"applicationTree",
        view: {
            dblClickExpand: false,
            showLine: true,
            selectedMulti: false
        },
        edit: {
            
        },
        data: {      
            simpleData: {
                enable:true
            }
        },
        callback: {
            
        }
    };
</script>

js中的其他几个为空,自己可以看文档配置

这里开启了简单的数据格式加载数据,数据格式如下

   {"id":1, "pId":0, "name":"test1"},
    {"id":11, "pId":1, "name":"test11"},
    {"id":12, "pId":1, "name":"test12"},
    {"id":111, "pId":11, "name":"test111"}

然后异步加载数据,后台返回数据格式的方法自己完成:

//页面加载
$(document).ready(function(){
    $.ajax({
        type:'post',
        url: "/perm/treeData",  //数据源
        dataType: "json",
        async: false,
        success: function (result) {
            if(result.code == "1"){
                zNodes = result.data;
                //初始化树
                t = $.fn.zTree.init(t, setting, zNodes); 
            }else{
                //layer.msg(result.info, {time: 1000, icon:2});
                console.log("error");
            }

        },
        error: function (msg) {
        }
    });
});

这样就可以加载树了

image.png

MyBatis插入对象后返回获得自增的主键

很多情况下,我们的主键都是自增的,我们可能在插入后马上就获取到刚刚插入的数据的主键,下面就来记录一下:

插入记录在MyBatis中的写法:

<insert id="saveXxx" parameterType="com.wjy329.entity.xxx">
      <selectKey resultType="Integer" order="AFTER" keyProperty="id">
          SELECT LAST_INSERT_ID()
      </selectKey>
        insert into tableName
		(
			`line2`,
			`line3`
		)
		values
		(
			#{line2},
			#{line3}
		)
</insert>

关键在于

 <selectKey resultType="Integer" order="AFTER" keyProperty="id">
          SELECT LAST_INSERT_ID()
 </selectKey>

你以为仅仅获取到这个就行了?那是不可能的,直接获取返回的int,你会发现是一个固定的数字,它代表刚才插入数据影响的行。

在执行完插入操作后,我们只需在后面直接用getId()方法就行,例如: 

studentDao.saveStudent(student);
Integer id = student.getId;

shell脚本报syntax error: unexpected end of file 错误

在Windows下用Sublime Text编写了脚本,上传到了服务器,然后高高兴兴一执行,出现了syntax error:unexpected end of file错误;在网上查了之后才知道,原来在Windows下写的脚本是dos格式的,而Linux服务器中只能执行unix格式的脚本。

解决方案:

  1.   vi  xxx.sh   用vi编辑脚本(或者vim)

  2. 输入  :set ff   回车,可以查看到当前脚本的格式,如果为fileformat=dos ,则需要修改脚本格式

  3. 输入  :set ff=unix    即可

  4. 再次输入  :set ff  查看脚本格式,如果输出为fileformat=unix,就成功了

  5. 执行脚本,ok