2015-09-18 11:08:02 qing_gee 阅读数 8297

前言:终于来了一篇有质量的文章,我个人感觉非常不错,《jfinal与bootstrap之间的登录跳转实战》。具体内容包含有点击登录弹出模态框、点击登录确认按钮后的validate、jfinal的validate、jfinal的session管理、ajax请求与返回信息处理、页面间智能跳转。

弹出模态框以及jquery validate可以参照jquery weebox总结弹出窗口不居中显示?jquery validate初上手系列文章。

从jfinal的validate说起

当然你可以参考jfinal提供的帮助文档,我当然也必须是参照了官方文档,当然对于这种开源技术每个人在使用的过程中肯定有千奇百态的问题,那么依据我的实战结果,我想再赘述一遍也是非常有必要的。

1.指定config中的路由

me.add("/login", MembersController.class, "/pages/login");

2.编写conroller类

public class MembersController extends BaseController {
    @Before(MembersValidator.class)
    @ActionKey("/login")
    public void login() {

        // 获取用户名
        String name = getPara("username");
        // 获取密码
        String password = getPara("password");

        Members mem = Members.me.getMemByNamePasswd(name, CipherUtils.generatePassword(password));

        if (mem != null) {
            // 保存session
            getSession().setAttribute("username", name);

            // 最后登录ip
            mem.set("lastip", getRequest().getRemoteHost());
            mem.set("lastvisit", DateUtils.getCurrentTime());

            mem.update();

            ajaxDoneSuccess("登录成功!");
        } else {
            ajaxDoneError("用户不存在!");
        }

        // 跳转到前台发起请求的路径
        renderJson();

    }
}

注意:

  1. 使用before绑定validate
  2. 使用actionkey绑定前端请求action名
  3. 使用getSession().setAttribute来操作session,同时前端稍后介绍如何使用
  4. 封装ajaxDone系列方法进行数据格式绑定,前端稍后介绍
  5. 使用renderJson方法对ajax请求返回结果数据进行json格式输出
  6. 接下来你需要看看我封装的baseController

3.BaseController

package com.hc.jf.controller;

import com.jfinal.core.Controller;

public class BaseController extends Controller {

    protected void ajaxDone(int statusCode, String message) {
        setAttr("statusCode", statusCode);
        setAttr("message", message);

        // 跳转路径
        String forwardUrl = getPara("forwardUrl");
        if (forwardUrl == null || forwardUrl.equals("")) {
            forwardUrl = getRequest().getRequestURL().toString();
        }

        setAttr("forwardUrl", forwardUrl);
        setAttr("callbackType", getPara("callbackType"));
    }

    protected void ajaxDoneSuccess(String message) {
        ajaxDone(200, message);
    }

    protected void ajaxDoneInfo(String message) {
        ajaxDone(201, message);
    }

    protected void ajaxDoneSuccess(String message, String forwarUrl) {
        ajaxDone(200, message);
    }

    protected void ajaxDoneError(String message) {
        ajaxDone(300, message);
    }

    protected void ajaxDoneError(String message, String forwarUrl) {
        ajaxDone(300, message);
    }
}

注意:

  1. 分别封装成功、错误、info级别的信息
  2. 增加了statusCode、message、forwardUrl、callbackType四个属性。
  3. 以上两个属性和前端也有对应,稍后介绍。

4.MembersValidator

package com.hc.jf.validator;

import com.hc.jf.entity.Members;
import com.jfinal.core.Controller;
import com.jfinal.validate.Validator;

public class MembersValidator extends Validator {

    @Override
    protected void validate(Controller controller) {
        validateRequiredString("username", "usernameMsg", "请输入用户名!");
        validateRequiredString("password", "passwordMsg", "请输入密码!");
    }

    @Override
    protected void handleError(Controller controller) {
        controller.keepModel(Members.class);
        controller.render("login.jsp");
    }

}

注意:

  1. 这个validate确实没什么屌用,因为前端已经使用jquery validate进行了check,然而请注意,如果你没有使用jquery的或者为了网络安全等等,有这个也不错。
  2. 好吧,我其实不想加入这个validate,但是我觉得可以我还没有想到用处,但是心有戚戚焉,觉得它还是有用的。

jfinal的session管理

其实说到这,已经不是jfinal的session了,其实要说的是前端。

<c:choose>
<c:when test="${sessionScope.username!=null}">
        <span>
            <a href="javascript:void(0);" id="mycenter" style="">
                ${sessionScope.username}<s class="icon_arrow icon_arrow_down"></s>
            </a>
            <i class="line"></i>
            <a href="/logout" title="退出" id="user_login_out" style="padding: 0 6px;">退出</a>
        </span>
        </c:when>
    <c:otherwise>
        <span>
            <a title="登录" href="javascript:show_pop_login();" id="show_pop_login">登录</a>
        </span>
    </c:otherwise>
</c:choose>

注意:

  1. 这里使用了${sessionScope.username}获取session数据,这只是很简单的一个应用。
  2. 1中好像没什么可说的,但重要的是,你弹出登录框后,需要重新回到对应的跳转页面,然后显示登录的信息,好吧,我觉得没有解释清楚,那么上一张图吧!
    这里写图片描述

这个图片为了商业机密,我只能截图到这里了,哈哈。
就像很多互联网网站一样,你如果是游客的话,也可以打开很多页面进行相关的信息进行查看,比如你可以打开1.html、2.html,但是这两个页面都可以点击登录按钮弹出登录框。那么问题来了,

你怎么保证从1.html打开登录的时候还跳转到1.html,从2.html打开登录成功后还跳转到2.html。

好吧,先说到这,这里卖个关子,我们继续看下个章节。

ajax请求与返回信息处理

1.弹出登录窗口

/**
 * 弹出登录框
 */
function show_pop_login() {
    $.weeboxs.open(common.ctx + "/pages/login/login.jsp", {
        boxid : 'pop_user_login',
        contentType : 'ajax',
        showButton : false,
        showCancel : false,
        showOk : false,
        title : '会员登录',
        width : 700,
        type : 'wee'
    });
}

这是弹出登录框,至于weebox,你可以查看jquery weebox总结

注意:

这里可能是从1.html打开的,也可能是从2.html页面打开的登录框。

2.然后我们再来看看登录的form表单

<form class="pop_login_form" action="${ctx}/login?callbackType=closeCurrent" method="post" onsubmit="return validateCallback(this, dialogAjaxDone);">
    <div class="row ">
        <div class="row">
            <label class="col-md-4" style="margin-top: 10px;" for="name">用户登录</label>
        </div>
        <div class="form-group">
            <div class="row">
                <div class="col-md-2 col-md-offset-2 tr th">
                    <label for="name">账户</label>
                </div>
                <div class="col-md-5">
                    <input type="text" style="" class="form-control required" id="username" name="username" placeholder="请输入会员编号"
                        autocomplete="off">
                </div>
            </div>
        </div>
        <div class="form-group">
            <div class="row">
                <div class="col-md-2 col-md-offset-2 tr th">
                    <label for="name">密码</label>
                </div>
                <div class="col-md-5">
                    <input type="password" class="form-control required" id="password" name="password" placeholder="请输入登陆密码">
                </div>
            </div>
        </div>
        <div class="row">
            <div class="checkbox">
                <label> <input type="checkbox"> 记住我(下次自动登陆)
                </label>
            </div>
        </div>
        <div class="row">
            <button type="submit" style="margin-bottom: 10px;" class="btn btn-default">提交</button>
        </div>
    </div>
</form>

注意:

  1. 你需要关注action=”${ctx}/login?callbackType=closeCurrent”
  2. 再关注onsubmit=”return validateCallback(this, dialogAjaxDone);”

好吧,我们先来看看登录的界面吧。
这里写图片描述

很漂亮的登录框,漂亮的不像实力派!嘻嘻。

然后关键的部分来了,请继续关注下节,我把发送ajax请求也放在下节的代码中,就省得重复。

页面间智能跳转

1.提交请求

/**
 * 普通ajax表单提交
 * 
 * @param {Object}
 *            form
 * @param {Object}
 *            callback
 * @param {String}
 *            confirmMsg 提示确认信息
 */
function validateCallback(form, callback, confirmMsg) {
    var $form = $(form);

    if (!$form.valid()) {
        return false;
    }

    var _submitFn = function() {
        var forwardUrl = window.location.href;
        var formUrl = $form.attr("action");
        if (formUrl.indexOf("?") != -1) {
            formUrl += "&forwardUrl=" + forwardUrl;
        } else {
            formUrl += "?forwardUrl=" + forwardUrl;
        }

        $.ajax({
            type : form.method || 'POST',
            url : formUrl,
            data : $form.serializeArray(),
            dataType : "json",
            cache : false,
            success : callback || YUNM.ajaxDone,
            error : YUNM.ajaxError
        });
    }

    if (confirmMsg) {
        alertMsg.confirm(confirmMsg, {
            okCall : _submitFn
        });
    } else {
        _submitFn();
    }

    return false;
}

好吧,看到这,你也许会说我剽窃了DWZ的灵感,OK,既然zhanghuihua同学开源了,有必要我们就好好的利用是吧。

注意:

  1. 你看到了forwardUrl的相关代码,没错,这个关键的字段就是来传递发起请求的页面路径,比如说1.html,2.html。
  2. 然后,ajax执行成功后,也就是登陆成功后,我们要执行callback方法,也就是dialogAjaxDone方法,那么你需要继续看下去。

2.回调函数

/**
 * dialog上的表单提交回调函数 服务器转回forwardUrl,可以重新载入指定的页面.
 * statusCode=YUNM.statusCode.ok表示操作成功, 自动关闭当前dialog
 */
function dialogAjaxDone(json) {
    YUNM.ajaxDone(json);
    if (json[YUNM.keys.statusCode] == YUNM.statusCode.ok || json[YUNM.keys.statusCode] == YUNM.statusCode.info) {
        if ("closeCurrent" == json.callbackType) {
            close_pop();
        }
        // 如果指定了后调转页面,进行调转
        if (json.forwardUrl) {
            location.href = json.forwardUrl;
        }
    }
}
    ajaxDone : function(json) {
        if (json[YUNM.keys.statusCode] == YUNM.statusCode.error) {
            if (json[YUNM.keys.message])
                $.showErr(json[YUNM.keys.message]);
            ;
        } else if (json[YUNM.keys.statusCode] == YUNM.statusCode.timeout) {
            alertMsg.error(json[YUNM.keys.message]);
        }
    },

注意:

  1. 第二串代码就是出于错误消息,诸如“用户不存在的”,还有timeout。
  2. 第一串代码就是回调函数,其作用就是成功后关闭弹出框,然后再跳转到对应页面。

这里写图片描述
这里写图片描述

结语:OK,这样一篇文章希望能够给热爱jfinal和bootstrap的同学带来灵感!

2014-01-28 13:05:20 robin_chenyu 阅读数 1779

Bootstrap2中同一页面实现多个modal

Bootstrap2中使用modal组件时,如果同一个页面使用多次,modal显示的内容全部是相同的。这种情况需要特殊处理下。

在页面尾部添加如下代码:

    $('#myModal').on('hidden', function () {
      $(this).removeData('modal');
    });

参考:

  1. stackoverflow faq
  2. modal multiple remote
2019-07-13 18:08:58 weixin_43996999 阅读数 246

个人总结

前言: 今天周末,闲来无事又看了看拦截器,发现不只是截获http请求,同样还可以制作很多好玩的东西,今天来写一个loading案例,请求http或者跳转渲染页面时,会有一定的等待时间,可能一两秒,也可能是十几秒,在等待的过程中,用户是不知道的,所以我们要给用户一个直观的等待效果,让用户知道!

步骤(需要引入的文件)

第一步: 引入bootstrap.css
第二步: 引入jquery库
第三步: 引入angular.js
第四步: 引入angular-ui-router.js
第五步: 引入angular-animate.js

下面看代码(需要的直接复制看效果就好!)

<!DOCTYPE html>
    <html lang="zh-CN" ng-app="myApp">
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="../../angularjs/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <style type="text/css">
            .mask-loading .loading-icon {
                -webkit-animation: rotate 1s linear infinite;
                -o-animation: rotate 1s linear infinite;
                animation: rotate 1s linear infinite;
                position: absolute;
                top: 50%;
                left: 50%;
                width: 30px;
                height: 30px;
                margin: -20px 0 0 -20px;
                border-width: 5px;
                border-style: solid;
                border-color: #37c3aa #37c3aa #fff #fff;
                opacity: .9;
                border-radius: 20px;
            }
     
            @-webkit-keyframes rotate{
              0% {-webkit-transform:rotate(0)}
              100% {-webkit-transform:rotate(360deg)}
            }
     
            @keyframes rotate{
              0% {transform:rotate(0)}
              100% {transform:rotate(360deg)}
            }
     
            .mask-loading {
              position:fixed;
              top:0;
              right:0;
              bottom:0;
              left:0;
              background:0 0;
              z-index:9999;
            }
        </style>
      </head>
      <body>
        <h1>index</h1>
        <div id="mask-loading" class="mask-loading" ng-if="loading" style="background-color: rgba(0, 0, 0, 0.17);">
            <div class="loading-icon"></div>
        </div>
        <div ui-view></div>
        <a ui-sref="a">go to a.html</a>
        <br/>
        <a ui-sref="b">go to b.html</a>
        <script src="../../angularjs/jquery-1.12.4.js"></script>
        <script src="../../angularjs/angular-1.5.8/angular.min.js"></script>
        <script type="text/javascript" src="./angular-animate.js"></script>
        <script type="text/javascript" src="./angular-ui-router.js"></script>
        <script type="text/javascript">
          var myApp = angular.module('myApp',['ui.router', 'ngAnimate']);
          myApp.config(["$stateProvider", "$httpProvider", '$urlRouterProvider', function ($stateProvider, $httpProvider, $urlRouterProvider) {
              $stateProvider
              .state('a', {
                  url: '/a',
                  templateUrl: "./a.html",
                  controller: "aController"
              })
              .state('b', {
                  url: '/b',
                  templateUrl: "./b.html",
                  controller: "bController"
              });
              $urlRouterProvider.otherwise('/');
              $httpProvider.interceptors.push('myInterceptor');
          }]);
           
          //loading拦截器
          myApp.factory('myInterceptor', ["$rootScope", function ($rootScope) {
              var timestampMarker = {
                  request: function (config) {   //请求前或跳转前或渲染后
                      $rootScope.loading = true;  // loading特效容器为true 显示
                      return config;
                  },
                  response: function (response) {   // 请求后或跳转后或渲染后
                    setTimeout(function(){//由于并没有调接口,所以体现不出来时间差距,为了体现有时间差,这里用到了定时器,
                        $rootScope.$apply(function(){  //重新脏检查
                            $rootScope.loading = false;   
                        });
                    },2000);
                      return response;
                  }
              };
              return timestampMarker;
          }]);
     
          myApp.controller('aController', function($scope) {
            $scope.page = "a";
          });
     
          myApp.controller('bController', function($scope) {
            $scope.page = "b";
          });
        </script>
      </body>
    </html>
2019-08-30 13:45:04 kelsey1234 阅读数 100

WEB前端bootstrap结合SSM框架

效果图:
在这里插入图片描述

step:
1. 后端接受请求跳转到html页面:html页面中相同的部分可以单独定义出来

eg:主html中定义head和div的th:replace="":第一个tag表示文件名,第二个tag表示fragment。div部分略
<!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org"
          lang="en">
    <head th:replace="common/tag::tag"/>
    <meta charset="utf-8">
    <body>
    <!-- 页面顶部¨ -->
    <div th:replace="common/head::head"/>

在这里插入图片描述

2. 对于表格部分只要定义个id即可,对于表格的操作(初始化,增删改)都定义到js中

<table id="rds_customer" class="table"></table>
 <script src="/tpl/rds_customer/rds_customer_list.js"></script>

3 .表格的初始化:

var properties = {
    //ajax url 和类型
    tableAjax : {
        url : '/rds_customer/findRdsCustomerList',
        type : "GET",
    },
    //table的html id
    tableId : 'rds_customer',//表的id
    uniqueId : 'id',//表的主键
    //table的列
    tableColumn : [ {
        checkbox : true,
        align : 'center'
    }, {
        field : 'id',
        title : '客户ID'
    }, {
        field : 'name',
        title : '客户名'
    }, {
        field : 'hobbies',
        title : '客户爱好'
    }, {
        field : 'gender',
        title : '客户性别'
    }, ]
};
$(function() {
    //初始化Table
    var oTable = new TableInit(properties);
    oTable.Init();
});

4.查询-分页查询:

  • 前端在js中定义pagination:true或者默认不写。后端用page,rows接收即可。
 @RequestMapping("/findRdsCustomerList")
   @ResponseBody()
    public DataGridResult findCustomerList(
    //defaultValue定义了每页默认显示5条记录
            @RequestParam(required = false, defaultValue = "1", value = "page") Integer page,
            @RequestParam(required = false, defaultValue = "5",value ="rows" ) Integer rows, ){
      return customerService.findCustomerList(page, rows);
   }
  • 在Controlle层或者Impl层写分页代码:
        PageHelper.startPage(page,rows);
       //中间省略了模糊查询的条件部分,后续
		List<RdsCustomer> customerList = rdsCustomerMapper.selectByExample(example);
        //查询的结果进行分页布置
        PageInfo<RdsCustomer> pageInfo = new PageInfo<RdsCustomer>(customerList);
        //封装成返回类型的结果
        DataGridResult result = new DataGridResult();
        //设置需要的参数
        result.setTotal(pageInfo.getTotal());
        result.setRows(customerList);
        //返回结果
        return result;
    } 
  • 将表格数据和分页信息封装成DataGridResult()直接返回到html页面,bootstrapTable会直接将数据和分页信息填充到表格中
  • ps1:springboot中使用分页插件直接导入pagehelper和autoconfigurer即可
		<dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-autoconfigure</artifactId>
            <version>1.2.5</version>
        </dependency>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.4</version>
        </dependency>
  • myBatis中使用分页插件则需要引入分页插件,然后在配置文件手动配置
<!-- 配置分页插件 -->
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库-->
    </plugin>
</plugins>
<!--加载mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/config/SqlMapConfig.xml" />
  • ps2:引入不同版本pagehelper页码形式也会有所不同

5.查询-模糊查询

  • 模糊查询先进入到html绘制模糊查询域,利用bootstrap即可绘制。注:form表单id必须与bootstrap中的queryParam中的选择器id保持一致,这样才能提交后端
 oTableInit.queryParams = function (params) {
        var param = {};
        $('#searchForm').find('[name]').each(function () {
            var value = $(this).val();
            if (value != '') {
                param[$(this).attr('name')] = value;
            }
        });
  • 查询按钮添加search()方法,当传入参数refreshOptions时,等于对表格重新初始化了,就会将queryParam中参数传递过去,并且刷新后的页码显示为第1页
function search() {
    $("#rds_customer").bootstrapTable('refreshOptions',{pageNumber:1});
}
  • 后端在原来基础上用RdsCustomer类接收
 @RequestMapping("/findRdsCustomerList")
   @ResponseBody()
    public DataGridResult findCustomerList(
            @RequestParam(required = true, defaultValue = "1", value = "page") Integer page,
            @RequestParam(required = true, defaultValue = "3",value ="rows" ) Integer rows, RdsCustomer rdsCostumer){
      return customerService.findCustomerList(page, rows,rdsCostumer);
   }
  • Impl类在分页查询的基础上增加example即可
	public class CustomerSerivceImpl implements CustomerService {
    Logger logger = LoggerFactory.getLogger(CustomerSerivceImpl.class);
    @Autowired
    private RdsCustomerMapper rdsCustomerMapper;
    @Override
    public DataGridResult findCustomerList(Integer page, Integer rows, RdsCustomer rdsCostumer) {
        PageHelper.startPage(page,rows);
        //组织好example
        RdsCustomerExample example = new RdsCustomerExample();
        //创建好条件标椎模板
        RdsCustomerExample.Criteria criteria = example.createCriteria();
        //查询条件:id要和文本框中一模一样
        if (StringUtil.isNotEmpty(rdsCostumer.getId())){
            criteria.andIdEqualTo(Integer.parseInt(rdsCostumer.getId()));
        }
        //查询条件:姓名和文本框类似
        if (StringUtil.isNotEmpty(rdsCostumer.getName())){
            criteria.andNameLike("%"+ rdsCostumer.getName() + "%");
        }
        //按照id进行排序
        example.setOrderByClause("id");
        //example模板准备好后进行查询
        List<RdsCustomer> customerList = rdsCustomerMapper.selectByExample(example);
        //查询的结果进行分页布置
        PageInfo<RdsCustomer> pageInfo = new PageInfo<RdsCustomer>(customerList);
        //封装成返回类型的结果
        DataGridResult result = new DataGridResult();
        //设置需要的参数
        result.setTotal(pageInfo.getTotal());
        result.setRows(customerList);
        //返回结果
        return result;
    }

6.新增:

  • 点击新增按钮弹出框:
    模态框中写的地址就是请求的地址
  • 新增界面要显示下一个新增进来的人的id:

Controller层:

@RequestMapping("/toAddRdsCustomerById")
    public String toAddCustomerPage(Model model){
        Long id  = customerService.getNextId();
        model.addAttribute("id",id);
        return "rds_customer/rds_customer_add";
   }

Impl层:

@Override
    public Long getNextId() {
        RdsCustomerExample example = new RdsCustomerExample();
        example.setOrderByClause("id desc");
        List<RdsCustomer> resultList = rdsCustomerMapper.selectByExample(example);
        //查询条件是按照id进行降序排序,然后获取到第一个集合的id,加1获取到的就是下一个新增的id
        return resultList.size()==0?10000:Long.parseLong(resultList.get(0).getId())+1;
    }
  • 填好新增信息后保存到数据库:保存触发addRdsCustomer()方法,bootatrap先进行正则校验,然后Ajax传数据并响应“增加用户成功”
function addRdsCustomer() {
        $('#addForm').data('bootstrapValidator').validate();
        if (!($('#addForm').data('bootstrapValidator').isValid())) {
            return;
        }
        $.mask_element('#addForm','数据保存中...');
        $.ajax({
            url : '/rds_customer/addRdsCustomer',
            data : $("#addForm").serialize(),
            success : function(result) {
                //请求成功时
                toastr.success('增加用户成功!');
                $(".close").click();
                search();
            }
        })
    }
  • 后端用一个封装好的类ReturnResult()接收
@RequestMapping("/addRdsCustomer")
   @ResponseBody
   public ReturnResult addRdsCustomer(RdsCustomer rdsCustomer){
        return ReturnResult.success(customerService.addCustomer(rdsCustomer));
   }
  • ReturnResult中代码
public class ReturnResult {
    //成功
	public static final int SUCCESS_CODE = 0;
    //失败
	public static final int ERROR_CODE = 1;
    //参数验证失败
	public static final int PARA_VALID_CODE = 12022;
    //自定义异常代码
	public static final int CUS_EX_CODE = 12023;
    //错误的请求
	public static final int BAD_REQUEST = 400;
    //未经授权
	public static final int UNAUTHORIZED = 401;
    //没有权限
	public static final int FORBIDDEN = 403;
    //没有找到
	public static final int NOT_FOUND = 404;
    //内部服务器错误
	public static final int INTERNAL_SERVER_ERROR = 500;
	
	
	private int code;
	/**
	 * 响应中的数据
	 */
	private Object data;
	/**
	 * 响应中的消息
	 */
	private String msg;

	public boolean isSuccess() {
		return SUCCESS_CODE==code;
	}

	public ReturnResult() {
	}

	public ReturnResult(int code, Object data, String msg) {
		super();
		this.code = code;
		this.data = data;
		this.msg = msg;
	}

	public int getCode() {
		return code;
	}

	public void setCode(int code) {
		this.code = code;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public static ReturnResult byCode(int code) {
		return new ReturnResult(code, "", null);
	}

	public static ReturnResult byCodeMsg(int code, String msg) {
		return new ReturnResult(code, null ,msg);
	}

	public static ReturnResult success() {
		return new ReturnResult(SUCCESS_CODE, null, null);
	}

	public static ReturnResult success(Object data) {
		return new ReturnResult(SUCCESS_CODE, data, null);
	}

	public static ReturnResult error(String msg) {
		return new ReturnResult(ERROR_CODE, null, msg);
	}

	public static ReturnResult error(Object data, String msg) {
		return new ReturnResult(ERROR_CODE, data, msg);
	}
}

function toAddCustomerById(){
    Dialog.modal({url:"/rds_customer/toAddRdsCustomerById"})
}

7.修改

  • 点击修改按钮触发 toUpdateRdsCustomerById()方法
  • var rows = $("#rds_customer").bootstrapTable(“getSelections”)
    获取到的rows是二维数组rows[i][‘j’],i表示选中记录的index,j是字段名
  • 将选中的那一条记录的id传到后端 后续操作和新增类似,略。
function toUpdateRdsCustomerById(){
    var rows = $("#rds_customer").bootstrapTable("getSelections");
    if (rows.length == 0){
        toastr.warning("请选择一条记录");
        return;
    }else if (rows.length > 1) {
        toastr.warning("只能选择一条记录");
        return;
    }
    Dialog.modal({url:"/rds_customer/toUpdatePage?id="+rows[0]['id']});
}

8.删除

  • 点击删除按钮跳转到deleteRdsCustomerByIds
  • 获取到被选中的所有记录,将记录中的所有id封装成对象ids,将ids传到后端
//获取表中所有被选中的记录:是数组
    var rows = $("#rds_customer").bootstrapTable("getSelections");
    //规定至少选择一条
    if (rows.length < 1){
        toastr.warning("请至少选择一条记录");
        return;
    }
    //获取到选择的那些记录的ids:对象
    var ids = {};
    for (var i = 0 ; i < rows.length ; i++){
        ids[i] = rows[i]['id'];
    }
  • 利用Ajax传到后端 并得到响应
 //将ids对象传到后端
    Dialog.confirm({
        message:"确认要删除数据吗?"
    }).on(function (e) {
        if (!e){
            return;
        }
        $.ajax({
            type:"POST",
            url:"/rds_customer/deleteRdsCustomerByIds",
            data:{
                ids:ids//传到后端的是ids对象
            },
            dataType:'json',
            success : function (data) {
                if (data.code == "0"){
                    toastr.warning("删除客户成功");
                    search();
                }else {
                    toastr.warning("删除顾客失败");
                }
            }
        });
    });
  • 后端IController层进行接收Impl进行删除操作
 @Override
    public int deleteCustomerByIds(RdsCustomer rdsCustomer) {
        RdsCustomerExample example = new RdsCustomerExample();
        example.createCriteria().andIdIn(rdsCustomer.getIds());
        return rdsCustomerMapper.deleteByExample(example);
    }
  • 所有增删改默认返回的都是SUCCESS_CODE,返回到前端,前端利用Ajax收到响应显示结果在界面上“XX用户成功!”。

8.在每一行加上操作按钮
在这里插入图片描述

  • 实现:在表格进行初始化时给按钮添加事件
var properties = {
    //tableAjax  url  数据接收类型  数据传输类型
    tableAjax: {
        url: "/fee/fee_data_list",
        dataType: "json",
        type: "GET"
    },
    tableId: 'datalist',
    //画table
    tableColumn : [{
        field: "id",
        title: "id"
    },{
        field: "name",
        title: "资费名称"
    },{
        field: "baseDuration",
        title: "基本时长"
    },{
        field: "baseCost",
        title: "基本费用"
    },{
        field: "unitCost",
        title: "单位费用"
    },{
        field: "status",
        title: "状态",
        formatter: function (value, row, index) {
            return changeStatusFormat(value);
        }
    },{
        field: "descr",
        title: "描述"
    },{
        field: "creatime",
        title: "创建时间",
        formatter: function (value, row, index) {
            return changeDateFormat(value);}
    },{
        field: "startime",
        title: "开通时间",
        formatter: function (value, row, index) {
            return changeDateFormat(value);}
    },{
        field:'operate',
        title:'操作',
        formatter:'operateFormatter'
    }]
};

$(function() {
    //初始化Table
    var oTable = new TableInit(properties);
    oTable.Init();
});

function operateFormatter(vlaue , row , index){
    if (row.status == "2"){
        return [
            ''
        ].join('');
    } else if (row.status == "1"){
        return [
            '<input type="button" class="btn_pause" onclick="changeStatus( '+ row.id +','+row.status+ ')" value="暂停">' +
            '<input type="button" class="btn_modify" onclick="modifyStatus(' + row.id +','+row.status+ ')" value="修改">' +
            '<input type="button" class="btn_delete" onclick="deleteStatus('+ row.id +','+row.status+ ')" value="删除">'
        ].join('');
    }else{
        return [
            '<input type="button" class="btn_start" onclick="changeStatus('+ row.id +','+row.status+')" value="开通">' +
            '<input type="button" class="btn_modify" onclick="modifyStatus(' + row.id +','+row.status+ ')" value="修改">' +
            '<input type="button" class="btn_delete" onclick="deleteStatus(' + row.id +','+row.status+ ')" value="删除">'
        ].join('');
    }
}

在这里插入图片描述

  • 实现:开通、暂停、删除按钮的功能 (开通、暂停时:表格数据发生改变同时按钮样式发生改变;删除时表格数据发生改变同时三个按钮消失)。开通、暂停公用一个方法:
function changeStatus(id,status){
    //将状态改为"1"class样式改为"btn_pause"开通后可以暂停
        $.ajax({
                type: "POST",
                url: "/fee/fee_start_status",
                datatype: "JSON",
                data: "id="+id+"&status="+status,
                success: function (data) {
                    if (data == "1"){
                        if (status == "0"){
                            toastr.warning("已暂停!");
                            search();
                        }else{
                            toastr.warning("已开通!");
                            search();
                        }
                    }else{
                        toastr.warning("开通失败!");
                    }
                }
        });
}
function deleteStatus(id , status) {
    //将所有状态删除
    $.ajax({
       url: "/fee/fee_delete_status",
       type: "POST",
       datatype: "JSON",
        data: "id="+id+"&status="+status,
        success: function (data) {
           if (data == "1"){
               toastr.warning("删除成功!");
               search();
               return;
           }
               toastr.warning("删除失败!");
        }
    });
}

9.bootstrap-table中的子父表
在这里插入图片描述

  • 在初始化表格的时候加上属性 detailView:true,表明显示子父表,加上此属性后表格最前列就会有“+”符号,然后在最后加上方法onExpandRow。如下:
   				detailView: true, //是否显示父子表
	            onLoadError :function(){
	            	var $errorMsg = $('<td colspan="12"><div class="m-error"><b class="error-icon">&nbsp;</b> <span class="error-text"><b class="text1">很抱歉,系统加载异常......</b><b class="text2"></b></span> </div></td>')	;   	
	    	 		$(".no-records-found").empty().append($errorMsg);	
	    	    },
                onExpandRow: function (index, row, $detail) {
	                oTableInit.InitSubTable(index,row, $detail);
                }
  • 初始化子表(实现InitSubTable方法)

      index:当前行的行索引
      row:父表当前行的Json数据
      $detail:当前行创建的td对象
    
   //父子表的实现
    oTableInit.InitSubTable = function (index, row, $detail) {
        var parentid = row.id;//将当前行的id传给属性parentid
        var cur_table = $detail.html('<table></table>').find('table');//创建子表cur_table
        $(cur_table).bootstrapTable({//初始化子表
            url: '/fee/fee_detail?id='+parentid,
            method: 'get',
            queryParams: { strParentID: parentid },
            ajaxOptions: { strParentID: parentid },
            pagination: false,
            columns: [{
            field: "id",
            title: "id"
        },{
            field: "name",
            title: "资费名称"
        },{
            field: "baseDuration",
            title: "基本时长",
        },{
            field: "baseCost",
            title: "基本费用",
        },{
            field: "unitCost",
            title: "单位费用"
        },{
            field: "status",
            title: "状态",
        },{
            field: "creatime",
            title: "创建时间",
            formatter: function (value, row, index) {
                return changeDateFormat(value);}
        },{
            field: "startime",
            title: "开通时间",
            formatter: function (value, row, index) {
                return changeDateFormat(value);}
        },{
                field: "descr",
                title: "描述"
            } ],
        });
    };

显示客户使用时长并进行排行(不使用表格的升降序符号)
根据id排序在这里插入图片描述

  • 点击“客户使用时长”按钮以及第一次进入该页面时都是按照id进行排序
  • 点击“时长排行榜”便是时长最高的前三名客户

前端代码:

		   <div class="tabs">
    	        <ul onclick="changeTab(event,this);">
        	        <li><a id="sumDuration" onclick="byDuration(1,2)" class="tab_on" title="每位客户每月的累计时长">客户使用时长</a></li>
                    <li><a id="durationRank" onclick="byDuration(1,2,3)" class="tab_out" title="每台服务器上累计时长最高的前三名客户">时长排行榜</a></li>
                </ul>
            </div>  

js中定义byDuration方法:这是为什么点击不同按钮会有不同表格的原因。刷新表格的属性:refreshOptions,
刷新的同时绑定属性:pageNumber,sortName,sortOrder

//时长排行榜
function byDuration(e) {
    //模拟方法的重载
    if (arguments.length == 2) {
        $("#datalist").bootstrapTable('refreshOptions',{pageNumber:1,sortName: "id",sortOrder: "asc"});
    }else if (arguments.length == 3) {
        $("#datalist").bootstrapTable('refreshOptions',{pageNumber:1,sortName: "sum_duration",sortOrder: "desc"});
    }
}

后端controller中代码:这是为什么第一进入该页面时显示使用时长的界面的原因。

    @GetMapping("/report/report_data_list")
    @ResponseBody
    public DataGridResult reportList(@RequestParam(defaultValue = "1" , value = "page" , required = true) Integer page,
                                     @RequestParam(defaultValue = "5" , value = "rows" , required = true) Integer rows,
                                     @RequestParam(defaultValue = "asc" , required = true , value = "order") String order ,
                                     @RequestParam(defaultValue = "id" , required = true , value = "orderName") String orderName){
        return reportService.findAllReport(page , rows, order , orderName);
    }

后端service中代码:主要是先进行降序排序,然后取出前三条记录。这是为什么能取出使用时长最长的三名用户的原因

 public DataGridResult findAllReport(Integer page , Integer rows , String order ,String orderName) {
        List<RdsReport> result = new ArrayList<>();
        List<RdsReport> rdsReportListByDuration = null;
        PageInfo<RdsReport> pageInfo = null;
        DataGridResult dataGridResult = new DataGridResult();
        PageHelper.startPage(page , rows);
        RdsReportExample example = new RdsReportExample();
        example.createCriteria().andIdIsNotNull();
        if (orderName.equals("sum_duration")){
            example.setOrderByClause(orderName + " " + order);
            rdsReportListByDuration = rdsReportMapper.selectByExample(example);
            result.add(0,rdsReportListByDuration.get(0));
            result.add(1,rdsReportListByDuration.get(1));
            result.add(2,rdsReportListByDuration.get(2));
            pageInfo = new PageInfo<>(result);
            dataGridResult.setRows(result);
        }else{
            example.setOrderByClause(orderName + " " + order);
            rdsReportListByDuration = rdsReportMapper.selectByExample(example);
            pageInfo = new PageInfo<>(rdsReportListByDuration);
            dataGridResult.setRows(rdsReportListByDuration);
        }
        dataGridResult.setTotal(pageInfo.getTotal());
        return dataGridResult;
    }
2019-03-09 10:16:30 weixin_43759829 阅读数 366

在这里插入图片描述
各种调试发现根本就没有进入success中,数据库能成功添加,但就是无法跳转到index.html,发现先页面总是自动重载,但是又没有写reload方法,于是去看前端代码发现:
在这里插入图片描述
提交和重置按钮的class值一样,怀疑是不是触发了reset,导致的重载页面,将class值改变之后发现确实是这样,最终解决问题!
在这里插入图片描述

没有更多推荐了,返回首页