JAVA项目spring、mybatis、springMVC 模态窗口,后端代码设计 | part2

JAVA项目(使用SSM实现)各部分详细分析(CRM)|| part2

5、创建市场活动

5.1 分析工作台页面结构

5.1.1页面切割技术

  • 早期技术
<frameset><frame><frameset>:用来切割页面.
                <frameset cols="20%,60%,20%" rows="10%,80%,10%">
    <frame>:显示页面.
                <frame src="url">

		<frameset cols="20%,60%,20%">
			<frame src="url1" name="f1">
			<frame src="url2" name="f2">
			<frame src="url3" name="f3">
		</frameset>
		
             每一个<frame>标签就是一个独立的浏览器窗口。

	     <a href="url" target="f3">test</a>
  • 现阶段主要使用技术<div>和<iframe>

 <div>:切割页面。<iframe>:显示页面。

<div style="height:10%;width=20%">

<div style="height:10%;width=20%">
	<iframe href="url">
</div>
  • 主页面举例(输入用户名和密码后登入的页面)
<!-- 顶部,用div切割页面,还没涉及到div中有网页 -->
<div id="top" style="height: 50px; background-color: #3C3C3C; width: 100%;">
	<div style="position: absolute; top: 5px; left: 0px; font-size: 30px; font-weight: 400; color: white; font-family: 'times new roman'">CRM &nbsp;<span style="font-size: 12px;">&copy;2019&nbsp;动力节点</span></div>
	<div style="position: absolute; top: 15px; right: 15px;">
		...
	</div>
</div>
	
<!-- 中间 -->
<div id="center" style="position: absolute;top: 50px; bottom: 30px; left: 0px; right: 0px;">
		
		<!-- 导航; 上面中间的div中又分一块div出来,占上面div的百分比,而不是全局的百分比 -->
		<div id="navigation" style="left: 0px; width: 18%; position: relative; height: 100%; overflow:auto;">
		...
		</div>
		
		<!-- 工作区:用于显示页面的,是网页了!注意 left: 18% 正好从导航区过来-->
		<div id="workarea" style="position: absolute; top : 0px; left: 18%; width: 82%; height: 100%;">
			<iframe style="border-width: 0px; width: 100%; height: 100%;" name="workareaFrame"></iframe>
		</div>
		
<!-- 底部 -->
<div id="down" style="height: 30px; width: 100%; position: absolute;bottom: 0px;"></div>		

注:HTML的相关知识
1、使用 <li> 标签定义的列表可以是个 无序列表也可以是有序列表
2、<a> 标签中的 target属性规定在何处(当前窗口或新开窗口)打开链接文档。
例如:<li class="liClass"><a href="workbench/main/index.do" target="workareaFrame">工作台</a></li>
点击这个超链接后,在页面加载完毕后有这个代码window.open("workbench/main/index.do","workareaFrame")

5.1.2 模态窗口

类似下面这样的实现就是模态窗口在这里插入图片描述

  • 模态窗口:模拟的窗口,本质上是<div>,通过设置z-index大小来实现的;
    初始时,z-index初始参数是<0,所以不显示;
    需要显示时,z-index值设置成>0即可。 bootstrap框架会自动控制z-index的大小。

例如:创建市场活动的模态窗口最外层div如下,modal代表模态窗口,fade代表不显示(对应toggle按下才显示)
<div class="modal fade" id="createActivityModal" role="dialog">

控制模态窗口的显示与隐藏:

  • 1)方式一:通过标签的属性data-toggle=“modal” data-target=“模态窗口的id” (美工喜欢用这种方式)

  • 2)方式二:通过js函数控制:
    选择器(选中div).modal(“show”);//显示选中的模态窗口
    选择器(选中div).modal(“hide”);//关闭选中的模态窗口

  • 3)方式三:通过标签的属性data-dismiss=“”
    点击添加了data-dismiss=""属性的标签,自动关闭该标签所在的模态窗口。

  • 模态窗口的意义:解决下面旧技术的复杂性
    window.open(“url”,“_blank”);
    模态窗口本质上就是原来页面中的一个<div>,只有一个页面;所有的操作都是在同一个页面中完成。

  • 代码举例:

<!-- 创建市场活动的模态窗口 -->
<div class="modal fade" id="createActivityModal" role="dialog">
	<div class="modal-dialog" role="document" style="width: 85%;">
		<div class="modal-content">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal">
					<span aria-hidden="true">×</span>
				</button>
				<h4 class="modal-title" id="myModalLabel1">创建市场活动</h4>
			</div>
			<div class="modal-body">
			
				<form id="createActivityForm" class="form-horizontal" role="form">
				
					<div class="form-group">
						<label for="create-marketActivityOwner" class="col-sm-2 control-label">所有者<span style="font-size: 15px; color: red;">*</span></label>
						<div class="col-sm-10" style="width: 300px;">
							<select class="form-control" id="create-marketActivityOwner">
							  <c:forEach items="${userList}" var="u">
								   <option value="${u.id}">${u.name}</option>
							  </c:forEach>
							</select>
						</div>
                           <label for="create-marketActivityName" class="col-sm-2 control-label">名称<span style="font-size: 15px; color: red;">*</span></label>
                           <div class="col-sm-10" style="width: 300px;">
                               <input type="text" class="form-control" id="create-marketActivityName">
                           </div>
					</div>
					...
			</div>
			<div class="modal-footer">
				<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
				<button type="button" class="btn btn-primary" id="saveCreateActivityBtn">保存</button>
			</div>
		</div>
	</div>
</div>
  • 对应按钮按下后模态窗口打开,使用的是jquery的标签选择器
$(function(){
    
    
	//给"创建"按钮添加单击事件
	$("#createActivityBtn").click(function () {
    
    
		//初始化工作
		//重置表单
		$("#createActivityForm").get(0).reset();

		//弹出创建市场活动的模态窗口
		$("#createActivityModal").modal("show");
	});

5.2 实现跳转

实现点击导航栏对应的超链接,实现跳转到对应的网页,网页的形式如下

<!-- 导航 -->
<div id="navigation" style="left: 0px; width: 18%; position: relative; height: 100%; overflow:auto;">

	<ul id="no1" class="nav nav-pills nav-stacked">
		<li class="liClass"><a href="main/index.html" target="workareaFrame"><span class="glyphicon glyphicon-home"></span> 工作台</a></li>
		...

<!-- 工作区 -->
<div id="workarea" style="position: absolute; top : 0px; left: 18%; width: 82%; height: 100%;">
	<iframe style="border-width: 0px; width: 100%; height: 100%;" name="workareaFrame"></iframe>
</div>

5.2.1 是否新创建一个独立的controller?

  • 方法:看跳转到的页面这个资源,是否占据一个独立的目录。
    比如现在要写个controller跳转到下面这个index.html,发现它在一个独立的main目录下,那么就要写一个新controller,所有main下的页面都在MainController中(每次写为@Controller之后去看包扫描了没有)。

  • Controller对应的@RequestMapping(“url”),其中url的规范是:从视图解析器向下走,到对应的资源路径,改为资源.do(优点就是在拦截器配置拦截路径的时候很方便)
    在这里插入图片描述

5.2.2 点击导航栏页面跳转实现

  • 点击超链接后跳到对应的controller进行处理,转发到对应的页面,再将页面从html改为jsp
<a href="main/index.html" target="workareaFrame">
<span class="glyphicon glyphicon-home"></span> 工作台</a>

<li class="liClass"><a href="activity/index.html" target="workareaFrame">
<span class="glyphicon glyphicon-play-circle"></span> 市场活动</a></li>
  • 将超链接改为对应的controller地址如:
<a href="workbench/main/index.do" target="workareaFrame"><span class="gl...

<li class="liClass"><a href="workbench/activity/index.do" target="workareaFrame">
<span class="gl...le"></span> 市场活动</a></li>
  • 编写controller
package com.bjpowernode.crm.workbench.web.controller;
@Controller
public class MainController {
    
    

    @RequestMapping("/workbench/main/index.do")
    public String index(){
    
    
        //跳转到main/index.jsp
        return "workbench/main/index";
    }
}
-------------------------------------------------------------
package cn.edu.uestc.crm.workbench.web.controller;
@Controller
public class ActivityIndexController {
    
    
    @RequestMapping("/workbench/activity/index.do")
    public String activityIndex(){
    
    
        return "workbench/activity/index";
    }
}

  • 用户每次完成登入,没有点击导航栏的“工作台”的时候,也应该默认显示出工作台,而不是点击才显示,如何做到?
    可以在用户登入后的index页面,在加载完毕的时候使用window.open(“url”,“指定窗口”),在“指定窗口中”打开url网页!注意看下面 工作区 iframe标签中name=“workareaFrame”
//页面加载完毕
$(function(){
    
    
	...
	window.open("workbench/main/index.do","workareaFrame");
	...

其中指定窗口在前端是这样的:name=“workareaFrame”,之前导航栏里面<a href="workbench/main/index.do" target="workareaFrame"> 这个target属性就规定在何处(当前窗口或新开窗口)打开链接文档。

<!-- 工作区,使用iframe就是使用网页形式 -->
<div id="workarea" style="position: absolute; top : 0px; left: 18%; width: 82%; height: 100%;">
	<iframe style="border-width: 0px; width: 100%; height: 100%;" name="workareaFrame"></iframe>
</div>

5.3 实现模态窗口下拉列表显示出数据库中的信息

思路很清晰,编写mapper(注意搜索的是settings下面的User,这里是登入的用户对应的那个表,对应的mapper写在settings文件夹下面),service,controller层对应代码,完成后端数据提交到前台,前台使用jstl标签库或者其他方式foreach循环出结果即可。

5.4 将创建的市场活动信息保存到后端数据库

  • 是否要新建一个controller?
    ----看服务器响应回来请求是在哪,显然,我们希望保存信息到服务器后端后,如果成功,则退出模态窗口,返回市场活动页面,还是在市场活动页面,所以不用新建一个包下放controller,新写一个方法即可。当然,可以在同一个包下写一个独立的controller,低耦合,方便维护。
  • 发生请求
    发的请求肯定是异步请求ajax,返回肯定也是返回数据给ajax,如果成功了,前端局部刷新,如果失败了模态窗口不退出,提示信息。还是需要一个json(是否成功的提示信息),前端解析这个json,判断成功还是不成功。如果成功,关闭模态窗口,不成功,那就提示信息。(这些都应该自己分析,自己做出来!
  • 思路
    传递参数,调用市场活动ActivityService、…mapper、…controller

5.4.1 后端代码

使用mybatis创建mapper-generator生成mapper(注意mapper是使用工具生成的,生成后需要添加包扫描),写出service都很简单,Controller有很多细节。

  • 前端参数封装为一个对象进行传输
    当前端有很多数据的时候,一个个接收肯定非常麻烦,springMVC的知识,浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参,如果接收那边是对象,会自动封装为对象(注意前端传的参数名和实体类的属性名要保存一致
  • 数据表参数封装
    数据库表那边的sql语句还要三个参数,是前端没有(很多情况是前端的数据全部都封装好了),对实体类activity进行二次封装。比如:activity.setCreateBy(user.getId());这个信息就是来自后端服务器的session(欢迎xxxx用户)。
  • 后端处理后,返回json格式的处理结果。
    做法很简单,只要在前端ajax请求上设置:dataType:"json",后端返回的思路是返回一个Object类型的数据,因为不需要返回具体的数据,直接将插入数据库成功\失败的结果封装到一个对象中传给前端就好了,这一点和登入的操作很像,可以复用同一个对象
public class RetObj {
    
    
    private String code; //处理成功、获取失败的标志 1---成功,0---失败
    private String message; //提示信息
    private Object retDate; //其他数据
	...
  • 插入数据insert操作,对于写的操作,要异常捕获! 读的一般不用
  • 整体代码:
@Controller
public class ActivityCreateController {
    
    

    @Resource
    ActivityService activityService;
    /**
     * 既然是面向ajax异步请求,返回的信息肯定带上ResponseBody啊!
     * 这段Controller方法是一个很好的练习机会,从前端到后端好好多理解,多次复习!
     * 参数:直接用Activity SpringMVC的知识, 前端传过来的参数自动封装为实体类对象!去复习!
     * @return Object 用了多态,具体返回的是Object的子类!
     */
    @ResponseBody
    @RequestMapping("/workbench/activity/saveCreateActivity.do")
    public Object saveCreateActivity(Activity activity, HttpSession session){
    
    

        //数据库表那边的sql语句还要三个参数,是前端没有,对实体类activity进行二次封装!
        User user = (User)session.getAttribute(Constants.SESSION_USER);
        activity.setId(UUIDUtils.getUUID());
        activity.setCreateBy(user.getId());
        activity.setEditTime(DateUtils.formattedNowDate(new Date()));

        //插入数据量,对于写的操作,要异常捕获! 读的一般不用
        //返回一个json格式的数据,用于告知前端是否成功
        RetObj retObj = new RetObj();

        int res = 0;
        try {
    
    
            res = activityService.insert(activity);
            if (res == 1){
    
    
                retObj.setCode(Constants.RETURN_OBJECT_CODE_SUCCESS);

            }else{
    
    
                retObj.setCode(Constants.RETURN_OBJECT_CODE_FAIL);
                retObj.setMessage("系统繁忙,请稍后尝试...");
            }
        } catch (Exception e) {
    
    
            e.printStackTrace();
            retObj.setCode(Constants.RETURN_OBJECT_CODE_FAIL);
            retObj.setMessage("系统繁忙,请稍后尝试...");
        }
        return retObj;
    }
}

5.5 前端ajax处理

  • 日期应该做一个日历,让用户直接选,所以不会导致格式问题,后续更新

  • 代码,和之前的登入的逻辑很像,都是获取按钮的内容作为参数使用ajax传给后端,这里多了模态窗口的开闭。

  • 注意清空模态窗口,每次创建完页面后,模态窗口是关闭的,但是里面div的内容是不变的,只是Z轴藏起来了,所以下次打开创建按钮,旧的数据还在,这个是应该清除的

$(function(){
    
    
		$("#createActivityBtn").click(function (){
    
    
			//弹出模态窗口
			$("#createActivityModal").modal("show");
		});

		//给创建市场活动的按钮绑定单机事件
		$("#saveCreateActivityBtn").click(function (){
    
    
			var owner = $("#create-marketActivityOwner").val();
			var name = $.trim($("#create-marketActivityName").val());
			var start_data = $("#create-startDate").val();
			var end_data = $("#create-endDate").val();
			var cost = $.trim($("#create-cost").val());
			var description = $.trim($("#create-describe").val());

			//提交表单前对对应栏目的数据进行判断,比如是否为空,日期的开始和结束时间对不对,数字的格式是否正确
			//这里判断,不行的直接return,接收刚刚点击按钮事件!能减小服务器后端的压力。
			if(owner == ""){
    
    
				alert("所有者不能为空!");
				return;
			}
			if(name == ""){
    
    alert("名称不能为空!");return;}
			//不能加引号!这个bug你找了很久(点击按钮没反应),后端不显示的,前端F12一下就能看出来!
			//var regExp="/^[1-9]\d*|0$/";
			var regExp = /^[1-9]\d*|0$/;
			if (!regExp.test(cost)){
    
    
				alert("成本只能是非负整数");
				return;
			}
			if (start_data != "" && end_data != ""){
    
    
				if (start_data > end_data){
    
    
					alert("开始时间不能够大于结束时间");
					return;
				}
			}

			//发送请求
			$.ajax({
    
    
				url:"workbench/activity/saveCreateActivity.do",
				data:{
    
    
					//这些参数和 后台实体类的属性保存一致!否则controller自动封装为对象不成功!
					owner:owner,
					name:name,
					cost:cost,
					startData:start_data,
					endData:end_data,
					description:description
				},
				type:"post",
				dataType:"json",
				success:function (data){
    
    
					//返回数据,如果后端成功了,关模态窗口,刷新界面。如果不成功,alert提示信息
					if (data.code == "1"){
    
    
						$("#createActivityModal").modal("hide");
						//刷新界面
					}else{
    
    
						alert(data.message);
						$("#createActivityModal").modal("show");
					}
				}
			});
		});
	})

持续更新中…

猜你喜欢

转载自blog.csdn.net/YiGeiGiaoGiao/article/details/129016588