动力节点-crm-项目笔记(待完善)

2年前 (2022) 程序员胖胖胖虎阿
378 0 0

文章目录

    • 1,搭建开发环境:
      • 1.1创建项目:crm-project
        • 1.1.1设置JDK.
        • 1.1.2创建工程:crm
        • 1.1.3补全目录结构:
        • 1.1.4设置编码格式:UTF-8
        • 1.1.5数据库编码设置
        • 1.1.6字符集编码的设置
    • 2.spring application配置文件知识点
      • 2.1.applicationContext-datasource.xml
        • 2.1.1.sqlsessionFactory他是一个数据库
        • 2.1.2为什么使用127.0.0.1不用localhost
      • 2.2 applicationContext-mvc.xml
        • 2.2.1服务器一起东就加载servlet实例 servlet会加载mvc的配置文件
        • 2.2.2拦截器
      • 2.3 applicationContext.xml
        • 2.3.1 监听器加载service层和dao层的配置文件
        • 2.3.2服务器启动对配置文件的加载顺序
      • 2.4 pom.xml
        • 2.4.1 `和`
        • 2.4.2maven对配置文件的编译
    • 3.tomcat和idea
        • 3.1idea项目是如何放在tomcat webapps下的
        • 3.2使用127.0.01ip地址
        • 3.3恢复代码提示的默认设置
    • 4.jsp
      • 4.1 jquery
        • 4.1.1 使用标签保存数据,以便在需要的时候能够获取到这些数据:
        • 4.1.2 jsp的运行原理:
        • 4.1.3 ajax $.each( )的用法
        • 4.1.4 submit发送同步,button通过绑定 发送异步
        • 4.1.5 jquery小结
        • 4.1.6 ajax
        • 4.1.7 jquery事件函数的用法:
      • 4.2 web
        • 4.2.1 cookie的参数传输
        • 4.2.2 cookie和session
        • 4.2.3 window.location.href
        • 4.2.4 jsp如何显示到浏览器上的
        • 4.2.5 jsp和html的编码区别
        • 4.2.6 `浏览器只能解决网页,json字符串只能由ajax和js来解决`
        • 4.2.7 index.jsp在根目录下自带base的标签的
        • 4.2.8 html中就加id 等html标签 就不要加js 的标签
        • 4.2.9 同步请求 (页面跳转了)
        • 4.2.10 整个页面加载完才执行入口函数
        • 4.2.11 web的作用域
        • 4.2.12

          s

          e

          s

          s

          i

          o

          n

          S

          c

          o

          p

          e

          .

          s

          e

          s

          s

          i

          o

          n

          U

          s

          e

          r

          .

          n

          a

          m

          e

          {sessionScope.sessionUser.name}和

          sessionScope.sessionUser.name{sessionUser.name}区别

      • 4.3. bootstrpt
        • 4.3.1 页面切割技术:`和:` ``
          和:``
        • 4.3.2 模态窗口
          • 模态窗口:
          • 控制模态窗口的显示与隐藏:
          • 模态窗口的意义:
        • 4.3.3 正则表达式
        • 4.3.4 日历
        • 4.3.5 日历用法
        • 4.3.6 分页插件
        • 4.3.7

1,搭建开发环境:
1)创建项目:crm-project
设置JDK.
创建工程:crm
补全目录结构:
设置编码格式:UTF-8
2)添加jar包:添加依赖—参考课件.
3)添加配置文件:参考课件.
4)添加静态页面资源:
webapps
|->stumgr
|->crm
|->.html,.css,.js,.img test.jsp
|->WEB-INF
|->web.xml
|->classes
|->lib
*web应用根目录下的内容都是不安全的,外界可以通过url直接访问;
所以,一般为了数据的安全,都会把页面放到WEB-INF下,因为WEB-INF目录下的资源是受保护的,外界不能直接访问。

1,搭建开发环境:

1.1创建项目:crm-project

1.1.1设置JDK.

动力节点-crm-项目笔记(待完善)

动力节点-crm-项目笔记(待完善)

1.1.2创建工程:crm

动力节点-crm-项目笔记(待完善)

动力节点-crm-项目笔记(待完善)

1.1.3补全目录结构:

动力节点-crm-项目笔记(待完善)

1.1.4设置编码格式:UTF-8

动力节点-crm-项目笔记(待完善)

动力节点-crm-项目笔记(待完善)

1.1.5数据库编码设置

动力节点-crm-项目笔记(待完善)

1.1.6字符集编码的设置

需要设置字节码的

  • 编码
  • 解码
  • 传输数据的字节码

动力节点-crm-项目笔记(待完善)

2.spring application配置文件知识点

2.1.applicationContext-datasource.xml

2.1.1.sqlsessionFactory他是一个数据库

动力节点-crm-项目笔记(待完善)

2.1.2为什么使用127.0.0.1不用localhost

localhost只是tomcat配置的一个映射,localhost是可以修改的有风险

动力节点-crm-项目笔记(待完善)

2.2 applicationContext-mvc.xml

2.2.1服务器一起东就加载servlet实例 servlet会加载mvc的配置文件

动力节点-crm-项目笔记(待完善)

<load-on-startup>1</load-on-startup> 服务器一起东就加载servlet实例

   <!-- Spring mvc分发servlet -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext-mvc.xml</param-value>
        </init-param>
       
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

2.2.2拦截器

​ a)提供拦截器类:implements HandlerInterceptor{
​ --pre
​ --post
​ --after
​ }
​ b)配置拦截器:springmvc.xml

能通过return ture 不能通过return false

配置拦截器

<mvc:interceptors>
    <mvc:interceptor>
        拦截的内容
        <mvc:mapping path="/settings/**"/>
        <mvc:mapping path="/workbench/**"/>
        放行的内容   有一个东西即要放行也要拦截,优先进行放行
        <mvc:exclude-mapping path="/settings/qx/user/toLogin.do"/>
        <mvc:exclude-mapping path="/settings/qx/user/login.do"/>
        <bean class="com.bjpowernode.crm.settings.web.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

<mvc:mapping path="/settings/**"/> 拦截的是url

settings/* 拦截一层目录 settings/*/login.jsp还是没拦截到

settings/** 拦截settins下所有目录

2.3 applicationContext.xml

2.3.1 监听器加载service层和dao层的配置文件

(applicationContext.xml,applicationContext-datasource.xml)

监听器在服务器一启动是就会进行加载

动力节点-crm-项目笔记(待完善)

2.3.2服务器启动对配置文件的加载顺序

服务器一启动就用监听器加载applicationContext.xml applicationContext.xml加载aplicationContext-datasource.xml aplicationContext-datasource.xml 会加载mybatis-config.xml

dispatcherservlet一启动就会加载application-mvc.xml配置文件

2.4 pom.xml

2.4.1 <groupId>和<artifactId>

动力节点-crm-项目笔记(待完善)

2.4.2maven对配置文件的编译

动力节点-crm-项目笔记(待完善)

maven默认只会编译java的源文件,不会编译xml配置文件

加上这个就会编译xml配置文件了

3.tomcat和idea

3.1idea项目是如何放在tomcat webapps下的

tomcat

webapps
|->stumgr
|->crm
|->.html,.css,.js,.img test.jsp
|->WEB-INF
|->web.xml
|->classes
|->lib

  • maven会把java代码,配置文件 编译好放在classes , 把依赖jar包放在lib目录下

  • 静态资源放在webapp下,会直接部署到tomcat webapps下的crm项目中根目录中

  • 页面要放在webapp web-inf下

  • 在crm根目录中能直接被访问,web-inf下的资源是受保护的不能直接访问,

  • 要通过controller跳转才能访问,到了controller后我们就能掌握主动权,对用用户进行验证

  • 为什么不将image,jquery放入web-inf下,这些东西放在web-inf下,因为要我们通过controller转发才能实现到页面上会非常麻烦,用一个要跳一个会非常麻烦

动力节点-crm-项目笔记(待完善)

3.2使用127.0.01ip地址

动力节点-crm-项目笔记(待完善)

3.3恢复代码提示的默认设置

动力节点-crm-项目笔记(待完善)

4.jsp

4.1 jquery

4.1.1 使用标签保存数据,以便在需要的时候能够获取到这些数据:

  • 给标签添加属性:

    如果是表单组件标签,优先使用value属性,只有value不方便使用时,使用自定义属性;

    如果不是表单组件标签,不推荐使用value,推荐使用自定义属性。

  • 获取属性值时:

    如果获取表单组件标签的value属性值:dom对象.value jquery对象.val()

    如果自定义的属性,不管是什么标签,只能用:jquery对象.attr(“属性名”);

不加引号会认为是变量,加了才认为是字符串

var activityId='${requestScope.activity.id}';
//删除活动备注
$("#deleteActivityRemark").click(function () {
   //获得自己创建的属性的值
   var id=$("#deleteActivityRemark").attr("remarkId");
   var activityId='${requestScope.activity.id}';
    
    
    
    
    <a class="myHref" remarkId="${remark.id}"  id="deleteActivityRemark" ><span class="glyphicon glyphicon-remove" style="font-size: 20px; color: #E6E6E6;"></span></a>
			

4.1.2 jsp的运行原理:

  1. xxx.jsp:
  • tocmat中运行:
    把xxx.jsp翻译成一个servlet,
    运行servlet,运行的结果是一个html网页
    把html网页输出到浏览器
  • html网页在浏览器上运行:
    先从上到下加载html网页到浏览器,在加载过程中,运行前端代码
    当页面都加载完成,再执行入口函数和js.
  1. 把页面片段显示在动态显示在页面中:
    • 选择器.html(htmlStr):覆盖显示在标签的内部
    • 选择器.text(htmlStr):覆盖显示在标签的内部
    • 选择器.append(htmlStr):追加显示在指定标签的内部的后边

4.1.3 ajax $.each( )的用法

success:function (data) {
				//显示总条数
				//$("#totalRowsB").text(data.totalRows);
				//显示市场活动的列表
				//遍历activityList,拼接所有行数据
				var htmlStr="";
				$.each(data.activityList,function (index,obj) {
					htmlStr+="<tr class=\"active\">";
					htmlStr+="<td><input type=\"checkbox\" value=\""+obj.id+"\"/></td>";
					htmlStr+="<td><a style=\"text-decoration: none; cursor: pointer;\" οnclick=\"window.location.href='detail.html';\">"+obj.name+"</a></td>";
					htmlStr+="<td>"+obj.owner+"</td>";
					htmlStr+="<td>"+obj.startDate+"</td>";
					htmlStr+="<td>"+obj.endDate+"</td>";
					htmlStr+="</tr>";
				});
				$("#tBody").html(htmlStr);

htmlStr+=“<tr class=“active”>”; 在"" 双引号中加 双引号 要在里面的双引号中 加上 \" 进行转义>

htmlStr+=“”+obj.owner+“”; 在"" 双引号中加 "+ +" 表示 obj.owner 不是一个字符,而是数据

4.1.4 submit发送同步,button通过绑定 发送异步

<input type="submit" value="发送同步请求">
<input type="button" id="queryBtu" value=" 通过id创建一个jquery对象绑定按钮,发送异步请求">

4.1.5 jquery小结

<script type="text/javascript">
   $(function () {
      $("#loginBtu").onclick(function () {
         var loginAct =$.trim ($("#loginAct").val());

         var loginPwd =$.trim( $("#loginPwd").val());

         var isRemPwd = $("#isRemPwd").prop("checkbox");

         
      })
   })
</script>
  • trim 方法是去掉空格

  • 使用jquery获取指定元素的指定属性的值:
    选择器.attr("属性名");//用来获取那些值不是true/false的属性的值.
    选择器.prop("属性名");//用来获取值是true/false的属性的值.例如:checked,selected,readonly,disabled等。

  • jquery中判断只有==和!=,因为是弱语言所以没有equel

  • 后台放送过去的是一个json(应该是returnObject对象自动变json)

  • (前端ajax定义好发送的就是json)后台接受的也是一个json

$("#msg").html(data.message);
$("#msg").text(data.message);
  • html即能写文本信息也能写标签信息

  • text 只能写标签信息

4.1.6 ajax

​ loginAct:loginAct,
​ loginPwd:loginPwd,
​ isRemPwd:isRemPwd

这种是不标准的未加双引号

//给"登录"按钮添加单击事件
			$("#loginBtn").click(function () {
				//收集参数
				var loginAct=$.trim($("#loginAct").val());
				var loginPwd=$.trim($("#loginPwd").val());
				var isRemPwd=$("#isRemPwd").prop("checked");
				//表单验证
				if(loginAct==""){
					alert("用户名不能为空");
					return;
				}
				if(loginPwd==""){
					alert("密码不能为空");
					return;
				}

				//显示正在验证
				//$("#msg").text("正在努力验证....");
				//发送请求
				$.ajax({
					url:"settings/qx/user/login.do",
					data:{
						"loginAct":loginAct,
						"loginPwd":loginPwd,
						"isRemPwd":isRemPwd
					},
					type:"post",
					dataType:"json",
					async:"false",
					success:function (data) {
						if(data.code=="1"){
							//跳转到业务主页面
							window.location.href="workbench/index.do";
						}else{
							//提示信息
							$("#msg").text(data.message);
						}
					},
					beforeSend:function () {//当ajax向后台发送请求之前,会自动执行本函数;
						//该函数的返回值能够决定ajax是否真正向后台发送请求:
						//如果该函数返回true,则ajax会真正向后台发送请求;否则,如果该函数返回false,则ajax放弃向后台发送请求。
						$("#msg").text("正在努力验证....");
						return true;
					}
				});
			});

4.1.7 jquery事件函数的用法:

  • 选择器.click(function(){//给指定的元素添加事件
    //js代码
    });
  • 选择器.click();//在指定的元素上模拟发生一次事件

4.2 web

4.2.1 cookie的参数传输

动力节点-crm-项目笔记(待完善)

4.2.2 cookie和session

在默认情况下,session对象在关闭浏览器后并不是立刻被销毁,因此,为了考虑系统的安全性,在用户退出时,需要即刻清除session对象,防止他人盗用session对象中的信息

其实在浏览器关闭后,session并没有失效,正常来说一个session的存活时间是30分钟,也就是在不操作这个session的情况下,30分钟自动清除。可是实际中浏览器关闭,设置的session也会随之消失,这里的消失是他这个session的你找不到了,不是他没有了,因为在浏览器重新打开时,浏览器总会自动给你创建一个的新的session。session并不是唯一的,每个session都有自己的一个专属sessionId,这个sessionId在浏览器打开时创建,保存在浏览器的cookie中,浏览器关闭,cookie自动清除,sessionId丢失,之前的session找寻不到!

cookie不销毁也会这样

4.2.3 window.location.href

window.location.href = "settings/qx/user/toLogin.do";

动力节点-crm-项目笔记(待完善)

4.2.4 jsp如何显示到浏览器上的

jsp就是一个servlet,先在tomcat运行,结果是一个html

4.2.5 jsp和html的编码区别

jsp默认是utf-8

html iso8859-1

4.2.6 浏览器只能解决网页,json字符串只能由ajax和js来解决

4.2.7 index.jsp在根目录下自带base的标签的

<%
	String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
%>

<base href="<%=basePath%>">

4.2.8 html中就加id 等html标签 就不要加js 的标签

动力节点-crm-项目笔记(待完善)

4.2.9 同步请求 (页面跳转了)

同步请求的方式 有地址栏,form表单,超链接 ajax只有地址栏一个方式 window.loction.href

4.2.10 整个页面加载完才执行入口函数

也就是静态资源加载完后

<script type="text/javascript">
    $(function () {
      
    });
</script>

4.2.11 web的作用域

jsp作用域

1,把控制层(controller)代码中处理好的数据传递到视图层(jsp),使用作用域传递:

pageContext:用来在同一个页面的不同标签之间传递数据。

jsp的每个标签对应着一个类 如<c:if 就对应着一个类

request:在同一个请求过程中间传递数据。

session: 同一个浏览器窗口的不同请求之间传递数据。

或者是一个用户的范围内

application:所有用户共享的数据,并且长久频繁使用的数据。

4.2.12

s

e

s

s

i

o

n

S

c

o

p

e

.

s

e

s

s

i

o

n

U

s

e

r

.

n

a

m

e

{sessionScope.sessionUser.name}和

sessionScope.sessionUser.name{sessionUser.name}区别

一个在指定的范围找 一个是在四个作用域所有的范围找

4.3. bootstrpt

4.3.1 页面切割技术:<frameset>和<frame>: <div>和<iframe>:

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>

2)<div>和<iframe>: 灵活效率高

<div>:切割页面。
        <div style="height:10%;width=20%">
    
</div>
</div>
 <iframe>:显示页面。
            <div style="height:10%;width=20%">
		<iframe href="url">
	    </div>
3,创建市场活动:

4.3.2 模态窗口

模态窗口:

模拟的窗口,本质上是<div>的一个表单,通过设置z-index大小来实现的; z轴
初始时,z-index初始参数是<0,所以不显示;
需要显示时,z-index值设置成>0即可。

    bootstrap来控制z-index的大小。
控制模态窗口的显示与隐藏:

​ 1)方式一:通过标签的属性data-toggle=“modal” 开启模态窗口 toggle切换 美工喜欢用

​ data-target=“模态窗口的id” 确定那个div是模态窗口

<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#createActivityModal"><span class="glyphicon glyphicon-plus"></span> 创建</button>

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

	$(function(){
		$("#createActivityBtu").click(function () {
			//这里可以编写js   进行一些初始化工作
			// jquery转dom对象  $("#createActivityFrom")  转为 from标签
			$("#createActivityFrom").get(0).reset();
			//弹出创建市场的窗口,
			$("#createActivityModal").modal("show");
		});
<!-- data-toggle="modal" data-target="#createActivityModal" 没有这两个前端属性-->
<button type="button" class="btn btn-primary"  id="createActivityBtu"><span class="glyphicon glyphicon-plus"></span> 创建</button>

​ 3)方式三:通过标签的属性data-dismiss=“”

​ 点击添加了data-dismiss=""属性的标签,自动关闭该标签所在的模态窗口。

模态窗口的意义:

​ window.open(“url”,“_blank”);
​ 模态窗口本质上就是原来页面中的一个<div>,只有一个页面;所有的操作都是在同一个页面中完成。

4.3.3 正则表达式

1.语言,语法,定义字符串的匹配模式,可以用来判断指定的具体字符串是否匹配模式

4.3.4 日历

js日历:

这一类问题:
1)实现起来比较复杂。
2)跟业务无关。

日历插件:bootstrap-datetimepicker
前端插件使用步骤:
1)引入开发包:.js,.css

`引入js`   <script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
`引入css`   <link href="jquery/bootstrap_3.3.0/css/bootstrap.min.css" type="text/css" rel="stylesheet" />

​ 下载开发包,拷贝到项目webapp目录下
​ 把开发包引入到jsp文件中:<link><script>
​ 2)创建容器:<input type="text"> 或 <div>
​ 3)当容器加载完成之后,对容器调用工具函数.

4.3.5 日历用法

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
%>
<html>
<head>
    <base href="<%=basePath%>">
<%-- jquery框架   --%>
    <script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>
<%-- 依赖于jquery的bootstrap框架--%>
    <script type="text/javascript"  src="jquery/bootstrap_3.3.0/js/bootstrap.min.js"></script>
<%--    <link rel="stylesheet" type="text/css" href="jquery/bootstrap_3.3.0/css/bootstrap-theme.min.css"/>--%>
    <link rel="stylesheet" type="text/css" href="jquery/bootstrap_3.3.0/css/bootstrap.min.css">
<%-- 依赖于bootstrap 的 日历插件   这些都要按顺序写才行 --%>
    <script type="text/javascript" src="jquery/bootstrap-datetimepicker-master/js/bootstrap-datetimepicker.min.js"></script>
    <script type="text/javascript" src="jquery/bootstrap-datetimepicker-master/locale/bootstrap-datetimepicker.zh-CN.js"></script>
    <link rel="stylesheet" type="text/css" href="jquery/bootstrap-datetimepicker-master/css/bootstrap-datetimepicker.min.css">

    <script type="text/javascript">
        $(function () {
            $("#myDate").datetimepicker({
                language:"zh-CN",
                format:"yyyy-mm-dd",
                minView:"month",
                initialDate:new Date(),
                autoclose:"true"
            });
        });
    </script>


    <title>Title</title>
</head>
<body>

<input type="text" id="myDate">
</body>
</html>

<%-- jquery框架 --%>

<%-- 依赖于jquery的bootstrap框架–%>

<%-- 依赖于bootstrap 的 日历插件 这些都要按顺序写才行 js是有顺序的 --%>

双标签

js的引用格式 <script type="text/javascript" src="jquery/jquery-1.11.1-min.js"></script>

单标签 没有自结束

css的引用 <link rel="stylesheet" type="text/css" href="jquery/bootstrap_3.3.0/css/bootstrap.min.css">

<script type="text/javascript">
 $(function () {
     $("#myDate").datetimepicker({
         language:"zh-CN",
         format:"yyyy-mm-dd",
         minView:"month", //最小的显示格式
         initialDate:new Date(),//初始的时间
         autoclose:"true"//选完时候自动关闭
     });
 });
</script>

入口函数注意用

}); }); 结尾

4.3.6 分页插件

<script type="text/javascript">
    $(function () {
        $("#demo_page").bs_pagination({
            currentPage: 1,//当前页号,相当于pageNo

            rowsPerPage: 10,//每页显示条数,相当于pageSize
            totalRows: 1000,//总条数
            totalPages: 100,  //总页数,必填参数.

            visiblePageLinks: 5,//最多可以显示的卡片数

            showGoToPage: true,//是否显示"跳转到"部分,默认true--显示
            showRowsPerPage: true,//是否显示"每页显示条数"部分。默认true--显示
            showRowsInfo: true,//是否显示记录的信息,默认true--显示

            //用户每次切换页号,都自动触发本函数;
            //每次返回切换页号之后的pageNo和pageSize
            onChangePage: function (event, pageObj) { // returns page_num and rows_per_page after a link has clicked
                //js代码
               // alert(pageObj.currentPage);//切换之后的 pageNo变化了
               // alert(pageObj.rowsPerPage);//切换之后  pageSize变化了
                
                  //onchangePage是触发事件 只有页数变换了才会触发改事件  不会发生递归
                                queryActivityByConditionForPage(pageObj.currentPage,pageObj.rowsPerPage)
            }
        });
    });
</script>

4.3.7 <link rel=“stylesheet” type=“text/css”

link标签是用于当前文档引用外部文档的,其次,这个标签的rel属性用于设置对象和链接目的间的关系,说白了就是指明你链进来的对象是个什么东西的, Stylesheet – 定义一个外部加载的样式表 type定义类型

4.3.8 html中的src与href的区别

写代码的时候就经常把这两个属性弄混淆,到底是href还是src,href标识超文本引用,用在linka等元素上,href是引用和页面关联,是在当前元素和引用资源之间建立联系,src表示引用资源,表示替换当前元素,用在imgscriptiframe上,src是页面内容不可缺少的一部分。

src是source的缩写,是指向外部资源的位置,指向的内部会迁入到文档中当前标签所在的位置;在请求src资源时会将其指向的资源下载并应用到当前文档中,例如js脚本,img图片和frame等元素。

当浏览器解析到这一句的时候会暂停其他资源的下载和处理,直至将该资源加载,编译,执行完毕,图片和框架等元素也是如此,类似于该元素所指向的资源嵌套如当前标签内,这也是为什么要把js饭再底部而不是头部。

<link href="common.css" rel="stylesheet"/>当浏览器解析到这一句的时候会识别该文档为css文件,会下载并且不会停止对当前文档的处理,这也是为什么建议使用link方式来加载css而不是使用@import。

4.3.9 class标签

动力节点-crm-项目笔记(待完善)

5. service

5.1.1 service层中,修改和查询的事务处理

  • 一个service方法代表一个事务

  • 查询的时候不要求两个方法放在同一个service方法中,

  • 修改的时候要求放在一个事务中,也就是同一个service方法中

5.1.2 service层的方法名一定要用(add,save,edit,update,delete,开头)

service层的方法名一定要用(add,save,edit,update,delete,开头)

(add,save,edit,update,delete,开头) 要就能进行修改的 报异常回滚

其他*只读 不能进行修改

<aop:config>
    <aop:pointcut expression="execution(* com.bjpowernode.crm..service.*.*(..))" id="allMethodPointcut"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="allMethodPointcut"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="do*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="*" propagation="REQUIRED" read-only="true"/>
    </tx:attributes>
</tx:advice>

6. Controller

6.0.1 controller的编写

动力节点-crm-项目笔记(待完善)

一个新静态资源的目录对应一个新的controller 对应的controller所在位置也在java对应的目录

6.0.2 Controller接受的url都要用.do结尾

用到一个新的静态资源,用一个新的controller

@RequestMapping("/workbench/activity/index.do")
 @RequestMapping("/workbench/activity/insertActivity.do")

web.xml

<!-- Spring mvc分发servlet    除了jsp页面不会经过个controller 其他的都会经过再进行处理-->
<servlet>
  <servlet-name>dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext-mvc.xml</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 欢迎页,默认进入index controller -->
<welcome-file-list>
  <welcome-file>/</welcome-file>
</welcome-file-list>

6.1. 传参问题

6.1.1 ajax向后台发送请求时,可以通过data提交参数,data的数据格式有三种格式:

1)data:{
k1:v1,
k2:v2,

}
*劣势:只能向后台提交一个参数名对应一个参数值的数据,
不能向后台提交一个参数名对应多个参数值的数据。
只能向后台提交字符串数据
优势:操作简单
2)data:k1=v1&k2:v2&…
*优势:不但能够向后台提交一个参数名对应一个参数值的数据,
还能向后台提交一个参数名对应多个参数值的数据。
劣势:操作麻烦
只能向后台提交字符串数据
3)data:FormData对象
优势:不但能提交字符串数据,
还能提交二进制数据
劣势:操作更复杂

data:FormData对象

$(function () {
    //给"导入"按钮添加单击事件
    $("#importActivityBtn").click(function () {
        //收集参数
        var activityFileName=$("#activityFile").val();
        var suffix=activityFileName.substr(activityFileName.lastIndexOf(".")+1).toLocaleLowerCase();//xls,XLS,Xls,xLs,....
        if(suffix!="xls"){
            alert("只支持xls文件");
            return;
        }
        var activityFile=$("#activityFile")[0].files[0];
        if(activityFile.size>5*1024*1024){
            alert("文件大小不超过5MB");
            return;
        }

        //FormData是ajax提供的接口,可以模拟键值对向后台提交参数;
        //FormData最大的优势是不但能提交文本数据,还能提交二进制数据
        var formData=new FormData();
        formData.append("activityFile",activityFile);
        formData.append("userName","张三");

        //发送请求
        $.ajax({
            url:'workbench/activity/importActivity.do',
            data:formData,
            processData:false,//设置ajax向后台提交参数之前,是否把参数统一转换成字符串:true--是,false--不是,默认是true
            contentType:false,//设置ajax向后台提交参数之前,是否把所有的参数统一按urlencoded编码:true--是,false--不是,默认是true
            type:'post',
            dataType:'json',
            success:function (data) {
                if(data.code=="1"){
                    //提示成功导入记录条数
                    alert("成功导入"+data.message+"条记录");
                    //关闭模态窗口
                    $("#importActivityModal").modal("hide");
                    //刷新市场活动列表,显示第一页数据,保持每页显示条数不变
                    queryActivityByConditionForPage(1,$("#demo_pag1").bs_pagination('getOption', 'rowsPerPage'));
                }else{
                    //提示信息
                    alert(data.message);
                    //模态窗口不关闭
                    $("#importActivityModal").modal("show");
                }
            }
        });
    });

6.1.2 controller的方法和mappersql语句 传参问题 用getKey得到参数 (参数是map)

map中的key要和mapper sql语句参数一致

动力节点-crm-项目笔记(待完善)

6.1.3 找到对应的activity类 对应的属性进行自动装配 用set方法进行装配的 (参数是activity实体类)

前端

<script type="text/javascript">
   $(function(){
      $("#saveActivity").click(function () {

         var activityOwner = $("#create-marketActivityOwner").val();
         var marketActivityName = $("#create-marketActivityName").val();
         var startTime = $("#create-startTime").val();
         var endTime = $("#create-endTime").val();
         var cost = $("#create-cost").val();
         var describe = $("#create-describe").val();
          
         if (activityOwner==""){
            alert("所有者不能为空!")
            return;
         }
         if(marketActivityName==""){
            alert("项目名称不能为空!")
            return;
         }
         $.ajax({
            url:"workbench/activity/insertActivity.do",
            data:{
               "owner":activityOwner,
               "name":marketActivityName,
               "startDate":startTime,
               "endDate":endTime,
               "cost":cost,
               "description":describe
            },
            dataType:"json",
            type:"post",
            success:function (data) {
               if(data.code=="1"){
                  $("#msg").text(data.message);
                  //跳转到业务主页面
                  window.location.href="workbench/activity/index.do";
               }else{
                  //提示信息
                  $("#msg").text(data.message);
               }
            }

         })
      })
   });
   
</script>

controller层

    @RequestMapping("/workbench/activity/insertActivity.do")
    @ResponseBody
    public Object insertActivity(Activity activity, HttpSession session) {

        User user =(User) session.getAttribute(Contants.SESSION_USER);
        activity.setId(UUIDUtils.getUUID());
        activity.setCreateTime(DateUtil.toFormatDate(new Date()));
        activity.setCreateBy(user.getId());
        ReturnObject returnObject = new ReturnObject();
        try {
            int i = activityService.insertActivity(activity);
            if (i>0){
                returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);
            }else {
                returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
                returnObject.setMessage("系统慢,请稍后.....");
            }
        }catch (Exception e){
            e.printStackTrace();
            returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
            returnObject.setMessage("系统慢,请稍后.....");
        }
        return returnObject;
    }

mapper层

  <insert id="insertActivity" parameterType="com.bjpowernode.crm.workbench.domain.Activity" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Mon May 09 21:11:52 CST 2022.
    -->
    insert into tbl_activity (id, owner, name, start_date, 
      end_date, cost, description, 
      create_time, create_by)
    values (#{id,jdbcType=CHAR}, #{owner,jdbcType=CHAR}, #{name,jdbcType=VARCHAR}, #{startDate,jdbcType=CHAR}, 
      #{endDate,jdbcType=CHAR}, #{cost,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR}, 
      #{createTime,jdbcType=CHAR}, #{createBy,jdbcType=VARCHAR})
  </insert>
/**
 *保存市场活动
 */
int insertActivity(Activity activity);

1.mapper.xml的 values (#{owner,jdbcType=CHAR} 中的owenerActivityowner对应

2.所以前端传过来的数据要能和Activity 的属性一致进行配对 之后用set方法自动赋值到 Activityowner,name,startDate属性

data:{
               "owner":activityOwner,
               "name":marketActivityName,
               "startDate":startTime,
               "endDate":endTime,
               "cost":cost,
               "description":describe
            }

6.1.4 什么样的java对象能通过springMVC 自动转成json对象传到后端

map list 实体类 数组

在后端到前端的时候 map能生成json对象 一般使用ReturnObject 工具实体类来生成(实体类效率高)

map一般慎用,因为效率太低了(链表+数组)动力节点-crm-项目笔记(待完善)

6.1.5 前端传过来的json 和controller参数名 和类型的对应

前端传过来的json只要参数名是对应的 就行,不要求前端json的数据类型是String,还是int类型的

因为前端只能向后台提交字符串数据

js是弱类型的语言

String name, String owner, String startDate, String endDate, int pageSize, int pageNo 前端传过来的json数据类型无论什么都可以 转换为int类型,和string类型

//String name, String owner, String startDate, String endDate, int pageSize, int pageNo  前端传过来的json对象成员可以 转换为int类型,和string类型
public Object queryActivityByConditionForPage(String name, String owner, String startDate, String endDate, int pageSize, int pageNo) {

    Map<String, Object> map = new HashMap<>();

    map.put("name", name);
    map.put("owner", owner);
    map.put("startDate", startDate);
    map.put("endDate", endDate);
    map.put("pageSize", pageSize);
    map.put("beginNo", (pageNo - 1) * pageSize);

6.1.6 ajax和后端的传参问题 (实体类activity传参)

动力节点-crm-项目笔记(待完善)

6.1.7 ajax向后端传json的id=xxxx&id=xxx&.....&id=xxx类型的数据 (string 数组传参问题)

后端接受的参数要和json中的参数名一致

动力节点-crm-项目笔记(待完善)

6.1.8 多条件查询封装函数

//带条件的查询

            $("#queryActivityBut").click(function () {
                queryActivityByConditionForPage("1","10");
            });


            //进入到首页的自动放在首页的查询
            queryActivityByConditionForPage("1","10");

            //多条件查询封装函数
            function queryActivityByConditionForPage(pageNo,pageSize) {
                var name = $("#query-name").val();
                var owner = $("#query-owner").val();
                var startTime = $("#query-startTime").val();
                var endTime = $("#query-endTime").val();
              /*  var pageNo = 1;
                var pageSize = 10;*/
                $.ajax({
                    url: "workbench/activity/queryActivityByConditionForPage.do",
                    data: {
                        name: name,
                        owner: owner,
                        startDate: startTime,
                        endDate: endTime,
                        pageNo: pageNo,
                        pageSize: pageSize
                    },
                    type: "post",
                    dataType: "json",
                    success: function (data) {
                        //显示总条数
                        //$("#totalRowsB").text(data.totalRows);
                        //显示市场活动的列表
                        //遍历activityList,拼接所有行数据
                        var htmlStr = "";
                        $.each(data.activityList, function (index, obj) {
                            htmlStr += "<tr class=\"active\">";
                            htmlStr += "<td><input type=\"checkbox\" value=\"" + obj.id + "\"/></td>";
                            htmlStr += "<td><a style=\"text-decoration: none; cursor: pointer;\" οnclick=\"window.location.href='detail.html';\">" + obj.name + "</a></td>";
                            htmlStr += "<td>" + obj.owner + "</td>";
                            htmlStr += "<td>" + obj.startDate + "</td>";
                            htmlStr += "<td>" + obj.endDate + "</td>";
                            htmlStr += "</tr>";
                        });
                        $("#tBody").html(htmlStr);

                    }
                });
            }

//多条件查询封装函数
function queryActivityByConditionForPage(pageNo,pageSize) { 在函数中直接写参数名,因为js是弱类型语言

6.1.9 ajax成功后读取封装后的实体类,要参照mapper中 (activity 传参)

动力节点-crm-项目笔记(待完善)

 queryActivityByConditionForPage("1",$("#demo_page").bs_pagination("getOption","rowsPerPage"));

记录上次的每页显示的条数bs_pagination("getOption","rowsPerPage"));

6.1.10 在javaweb阶段 json传参

后端 UserServlet 程序中 ajaxExistsUsername 方法:

protected void ajaxExistsUsername(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException {
// 获取请求的参数 username
String username = req.getParameter("username");
// 调用 userService.existsUsername();
boolean existsUsername = userService.existsUsername(username);
// 把返回的结果封装成为 map 对象
Map<String,Object> resultMap = new HashMap<>();
resultMap.put("existsUsername",existsUsername);
Gson gson = new Gson();
String json = gson.toJson(resultMap);
resp.getWriter().write(json);
}

springMVC将这个方法进行自动处理一个returnObject

// 把返回的结果封装成为 map 对象
Map<String,Object> resultMap = new HashMap<>();
resultMap.put("existsUsername",existsUsername);
Gson gson = new Gson();
String json = gson.toJson(resultMap);
resp.getWriter().write(json);

前端 regist.jsp 页面中的代码

("#username").blur(function () {
//1 获取用户名
var username = this.value;
$.getJSON("http://localhost:8080/book/userServlet","action=ajaxExistsUsername&username=" +
username,function (data) {
if (data.existsUsername) {
$("span.errorMsg").text("用户名已存在!");
} else {
$("span.errorMsg").text("用户名可用!");
}
});
});

6.1.11 success:function (data) { 中的data代表的东西

动力节点-crm-项目笔记(待完善)

6.1.12 想要返回的 json对象更加的通用一般返回值用Object

6.1.13 全部请求还是异步请求

  • 如果是刷新整个页面就用同步
  • 如果是刷新部分页面就用异步
  • 如果不确定是全部还是异步就用异步

7. 业务思想

7.0.1 User是系统管理功能 Activity业务管理功能

7.0.2 跟用户相关的是系统功能 要写在 setting文件目录下

7.0.3 做业务功能的先后顺序

功能选择

先做被依赖的功能,比如登录

7.0.4 为什么使用public修饰方法

动力节点-crm-项目笔记(待完善)

8. mybatis

8.1. mapper

8.1.1 连接查询 d.value as c.appellation 是错误的

动力节点-crm-项目笔记(待完善)

动力节点-crm-项目笔记(待完善)

8.1.2 构建表未使用外键

动力节点-crm-项目笔记(待完善)

8.1.3 排除多条记录 not in 排除一条记录 !=

mapper.xml LIKE '%'#{activityName}'%' %要加一个单引号变成'%'

SELECT a.`id`, a.`name`, a.`start_date`, a.`end_date`, u.`name` AS OWNER
FROM `tbl_activity` a
         JOIN `tbl_user` u ON u.`id` = a.`owner`
WHERE a.`name` LIKE '%'#{activityName}'%'
AND a.`id` NOT IN
      (SELECT activity_id
       FROM `tbl_clue_activity_relation`
       WHERE clue_id=#{clueId}
    )

sql语句是 LIKE '%发%'

SELECT a.`id`,a.`name`,a.`start_date`,a.`end_date`,u.`name` AS OWNER
FROM `tbl_activity` a
JOIN `tbl_user` u ON u.`id`=a.`owner` 
WHERE a.`name` LIKE  '%发%'
AND a.`id` NOT IN
(SELECT activity_id
FROM `tbl_clue_activity_relation`
WHERE clue_id='e9170a45c96d4a83800b2599c4f56c18'
)

8.1.4 连接表的效率比较

连接了两张表

    <select id="selectActivityByActivityArrayId" parameterType="string" resultMap="BaseResultMap">
        select a.id, a.name, a.start_date, a.end_date, u.name as owner
        from tbl_activity a
                 join tbl_user u on a.owner = u.id
where  a.id=   in  //效果就是(xx,xx,xx)//
<foreach collection="array" item="id" separator="," open="(" close=")">
    #{id}
</foreach>
    </select>

连接了三张表 效率低

<select id="selectActivityForDetailByClueId" parameterType="string" resultMap="BaseResultMap">
    select a.id, a.name, a.start_date, a.end_date, u.name as owner
    from tbl_activity a
             join tbl_user u on a.owner = u.id
             join tbl_clue_activity_relation car on a.id = car.activity_id
    where car.clue_id = #{clueId}
</select>

8.1.5 select添加string参数 (list)

dao

int insertMultipleActivity (List<ClueActivityRelation> ClueActivityRelations);

mapper.xml insert插入多条数据

separator=“,” 是对 <foreach > 标签中的内容遍历一次进行一次 分割 ,

        parameterType="com.bjpowernode.crm.workbench.domain.ClueActivityRelation">
    insert into tbl_clue_activity_relation (id, clue_id, activity_id)
    values
    <foreach collection="list" item="obj" separator=",">
        (#{obj.id}, #{obj.clueId}, #{obj.activityId} )
    </foreach>
</insert>

sql语句 insert插入多条数据

  INSERT INTO tbl_clue_activity_relation (id, clue_id, activity_id)
    VALUES 
    (1245,21,21),
(2455,2,2)

8.1.6 内连接和外连接

内连接(自然连接)会只会显示配数据,舍弃不匹配数据,外连接不会舍弃,所以两个表都能匹配就用内连接

看外键是否为空在采取,内连接还是外联接

不为空自然链接就能查出来,为空要外联接查出可能为空的数据

8.1.6 带 in 的查询 (参数是 string数组)

注意:where a.id in 要写a.id,要不然不知到id是谁的id

mapper.xml

    <select id="selectActivityByActivityArrayId" parameterType="string" resultMap="BaseResultMap">
        select a.id, a.name, a.start_date, a.end_date, u.name as owner
        from tbl_activity a
                 join tbl_user u on a.owner = u.id
where in a.id=     //效果就是(xx,xx,xx)//
<foreach collection="array" item="id" separator="," open="(" close=")">
    #{id}
</foreach>
    </select>

<foreach collection="array" item="id" separator="," open="(" close=")"> #{id} </foreach>

没遍历一个id就加一个 , 的分隔符 遍历完后就 在前面后面分别加上 ( )

8.1.7 方法的参数数量和mapper.xml中sql语句关系

​ 在MyBatis进行操作:
​ *** 1:如果操作方法只有一个简单类型或者字符串类型的参数,**
​ *** 在Mapper配置中可以直接通过#{key}获取,这个key的占位符号可以随便写**

​ *** 2:如果操作方法有一个对象类型的参数,**
​ *** 在Mapper配置中可以直接通过#{attrName}获取对象的指定属性值(attrName必须是参数对象的属性)**

​ *** 3:如果操作方法有一个Map类型的参数,**
​ *** 在Mapper配置中可以直接通过#{key}获取key的指定value值**

​ *** 4:如果操作方法有多个参数,该如何处理呢?**
​ *** 通过MyBatis自带的参数 arg0 arg1 … 来获取相应的参数**
​ *** 也可以通过在方法的参数中加入@Param(“key”) 给参数添加注解的方式**

动力节点-crm-项目笔记(待完善)

8.1.8 mapper.xml 查询和修改的语句返回值的区别

mapper.xml中的 修改语句压根没有定义resultType resultMap语句 加上反而会错

只有查询语句才有resultMap和resultType

<select id="selectActivityByConditionForPage" parameterType="map" resultMap="BaseResultMap">
  <select id="selectCountOfActivityByCondition" parameterType="map" resultType="int">

8.2. mybatis逆向工程

动力节点-crm-项目笔记(待完善)

8.2.1 配置文件设置

动力节点-crm-项目笔记(待完善)

动力节点-crm-项目笔记(待完善)

8.2.2 插件和jar包的区别

  • jar只能让别人去调用
  • 插件是可以自己运行的程序

动力节点-crm-项目笔记(待完善)

9. 细节

9.0.1 业务和系统

dicValue 字典是系统的东西 但是字典内容映射到前台是业务层的controller

线索clue是业务层的东西

9.0.2 列选择模式

动力节点-crm-项目笔记(待完善)

9.0.3 在idea中添加try/catch的快捷键

ctrl+alt+t 选中想被try/catch包围的语句,同时按下ctrl+alt+t, 出现下图 动力节点-crm-项目笔记(待完善)

9.0.4 json对象和json数组的区分

  • json对象 外面是大括号{}

  • json数组 外面是中括号 []

9.0.5 String contains 用法

user.getAllowIps().contains(request.getRemoteAddr()) 确定大的里面是否有小的

} else if (!user.getAllowIps().contains(request.getRemoteAddr())) {
    //访问的ip地址未在允许的ip访问
    returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
    returnObject.setMessage("访问的ip地址未在允许的ip访问");

9.0.6 前后端传url的时候尽量ctrl c ctrl v 不是自己手打

9.0.7 debug可以边修改边debug

9.0.8 ajax访问时,如果url没有写对,就会访问一个空的页面,因为在controller中找不到

9.0.9 为将来修改删除做准备,要查询id 能多地方都要传值要用到 id

9.0.10 mapper.xml 批量删除和多条件查询

  <insert id="insertActivity" parameterType="com.bjpowernode.crm.workbench.domain.Activity" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Mon May 09 21:11:52 CST 2022.
    -->
    insert into tbl_activity (id, owner, name, start_date,
    end_date, cost, description,
    create_time, create_by)
    values (#{id,jdbcType=CHAR}, #{owner,jdbcType=CHAR}, #{name,jdbcType=VARCHAR}, #{startDate,jdbcType=CHAR},
    #{endDate,jdbcType=CHAR}, #{cost,jdbcType=VARCHAR}, #{description,jdbcType=VARCHAR},
    #{createTime,jdbcType=CHAR}, #{createBy,jdbcType=VARCHAR})
  </insert>

  <select id="selectActivityByConditionForPage" parameterType="map" resultMap="BaseResultMap">
    select a.id,u1.name as owner,a.name,a.start_date,a.end_date,a.cost,a.description,a.create_time,
    u2.name as create_by,a.edit_time,u3.name as edit_by
    from tbl_activity a
    join tbl_user u1 on a.owner=u1.id
    join tbl_user u2 on a.create_by=u2.id
    left join tbl_user u3 on a.edit_by=u3.id
    <where>
      <if test="name!=null and name!=''">
        and a.name like '%' #{name} '%'
      </if>
      <if test="owner!=null and owner!=''">
        and u1.name like '%' #{owner} '%'
      </if>
      <if test="startDate!=null and startDate!=''">
        and a.start_date&gt;=#{startDate}
      </if>
      <if test="endDate!=null and endDate!=''">
        and a.end_date&lt;=#{endDate}
      </if>
    </where>
    order by a.create_time desc
    limit #{beginNo},#{pageSize}
  </select>

  <select id="selectCountOfActivityByCondition" parameterType="map" resultType="int">
    select count(*)
    from tbl_activity a
    join tbl_user u1 on a.owner=u1.id
    join tbl_user u2 on a.create_by=u2.id
    left join tbl_user u3 on a.edit_by=u3.id
    <where>
      <if test="name!=null and name!=''">
        and a.name like '%' #{name} '%'
      </if>
      <if test="owner!=null and owner!=''">
        and u1.name like '%' #{owner} '%'
      </if>
      <if test="startDate!=null and startDate!=''">
        and a.start_date&gt;=#{startDate}
      </if>
      <if test="endDate!=null and endDate!=''">
        and a.end_date&lt;=#{endDate}
      </if>
    </where>
  </select>

  <delete id="deleteActivityByIds" parameterType="string">
    delete from tbl_activity where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
  #{id}
</foreach>
  </delete>

9.0.11 $(“#updateActivityBtn”).click(function () { 失效可能的原因

//更新修改的参数 单击事件后面没有加 ); 是没有关系的 没有放在$(function())中有关系
$(“#updateActivityBtn”).click(function () {

10. 市场活动

10.1 导出市场活动:

@RequestMapping("/workbench/activity/exportPartActivity.do")
public void  exportAllActivity(HttpServletResponse response,String [] id) throws IOException {
    List<Activity> activityList = activityService.queryPartActivity(id);

    HSSFWorkbook workbook = new HSSFWorkbook();
    HSSFSheet sheet = workbook.createSheet("市场活动列表");
    HSSFRow row = sheet.createRow(0);
    HSSFCell cell = row.createCell(0);
    cell.setCellValue("id");
    cell= row.createCell(1);
    cell.setCellValue("拥有者");
    cell= row.createCell(2);
    cell.setCellValue("项目名称");
    cell= row.createCell(3);
    cell.setCellValue("开始时间");
    cell= row.createCell(4);
    cell.setCellValue("结束时间");
    cell= row.createCell(5);
    cell.setCellValue("花费");
    cell= row.createCell(6);
    cell.setCellValue("描述");
    cell= row.createCell(7);
    cell.setCellValue("创建时间");
    cell= row.createCell(8);
    cell.setCellValue("创建者");
    cell= row.createCell(9);
    cell.setCellValue("修改时间");
    cell= row.createCell(10);
    cell.setCellValue("修改者");

    if (activityList.size()>0&&activityList!=null){
        Activity activity=null;
        for (int i = 0; i < activityList.size(); i++) {
            //    Activity  activity = activityList.get(i);
            activity = activityList.get(i);
            //sheet.createRow(i+1);
            row=sheet.createRow(i+1);

            cell = row.createCell(0);
            cell.setCellValue(activity.getId());
            cell= row.createCell(1);
            cell.setCellValue(activity.getOwner());
            cell= row.createCell(2);
            cell.setCellValue(activity.getName());
            cell= row.createCell(3);
            cell.setCellValue(activity.getStartDate());
            cell= row.createCell(4);
            cell.setCellValue(activity.getEndDate());
            cell= row.createCell(5);
            cell.setCellValue(activity.getCost());
            cell= row.createCell(6);
            cell.setCellValue(activity.getDescription());
            cell= row.createCell(7);
            cell.setCellValue(activity.getCreateTime());
            cell= row.createCell(8);
            cell.setCellValue(activity.getCreateBy());
            cell= row.createCell(9);
            cell.setCellValue(activity.getEditTime());
            cell= row.createCell(10);
            cell.setCellValue(activity.getEditBy());
        }
    }

    //FileOutputStream os = new FileOutputStream("D:\\Desktop\\word文档\\demo.xls");
    //  workbook.write(os);

    //  os.close();
    //  workbook.close();

    //1.设置响应类型
    response.setContentType("application/octet-stream;charset=UTF-8");

    //2.获取输出流
    OutputStream out=response.getOutputStream();

    //浏览器接收到响应信息之后,默认情况下,直接在显示窗口中打开响应信息;即使打不开,也会调用应用程序打开;只有实在打不开,才会激活文件下载窗口。
    //可以设置响应头信息,使浏览器接收到响应信息之后,直接激活文件下载窗口,即使能打开也不打开
    response.addHeader("Content-Disposition","attachment;filename=mystudentList.xls");

    //读取excel文件(InputStream),把输出到浏览器(OutoutStream)
   /* InputStream is=new FileInputStream("D:\\Desktop\\word文档\\test1.xls");
    byte[] buff=new byte[256];
    int len=0;
    while((len=is.read(buff))!=-1){
        out.write(buff,0,len);
    }*/

    //关闭资源
    // is.close();
    workbook.write(out);

    workbook.close();
    out.flush();

}

1)给"批量导出"按钮添加单击事件,发送导出请求
2)查询所有的市场活动
3)创建一个excel文件,并且把市场活动写到excel文件中
4)把生成的excel文件输出到浏览器(文件下载)

技术准备:
1)使用java生成excel文件:iText,apache-poi

     关于办公文档插件使用的基本思想:把办公文档的所有元素封装成普通的Java类,
                                 程序员通过操作这些类达到操作办公文档目的。
 文件---------HSSFWorkbook
 页-----------HSSFSheet
 行-----------HSSFRow
 列-----------HSSFCell
 样式---------HSSFCellStyle

 使用apache-poi生成excel:
     a)添加依赖:
            <dependency>
	      <groupId>org.apache.poi</groupId>
	      <artifactId>poi</artifactId>
	      <version>3.15</version>
	    </dependency>
     b)使用封装类生成excel文件:
       
   2)文件下载:
     filedownloadtest.jsp
     ActivityController
     |->fileDownload()

 *所有文件下载的请求只能发送同步请求。

*所有文件下载的请求只能发送同步请求。

异步请求只能接受json的对象 不能接受文件

要想接受文件只能发送同步请求

10.1.1 用pio生成excel

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CreateExcelTest {
    public static void main(String[] args) throws IOException {//用main来代替客户端 调用java代码
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
        HSSFSheet sheet = hssfWorkbook.createSheet("学生表");
        HSSFRow row = sheet.createRow(0);
        HSSFCell cell = row.createCell(0);
        cell.setCellValue("学号");
        cell = row.createCell(1);
        cell.setCellValue("姓名");
        cell = row.createCell(2);
        cell.setCellValue("年龄");

        for (int i = 1; i <= 10; i++) {
            row = sheet.createRow(i);
            cell = row.createCell(0);
            cell.setCellValue(1000 + i);
            cell = row.createCell(1);
            cell.setCellValue("zwj" + i);
            cell = row.createCell(2);
            cell.setCellValue(i);
        }
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\Desktop\\word文档\\test1.xls");
        hssfWorkbook.write(fileOutputStream);

        fileOutputStream.close();
        hssfWorkbook.close();
        System.out.println(" ==========ok========");
    }
}

cell =

//用main来代替客户端 调用java代码

10.1.2 浏览器对在服务器进行文件下载

1.设置响应类型
response.setContentType("application/octet-stream;charset=UTF-8");

动力节点-crm-项目笔记(待完善)

动力节点-crm-项目笔记(待完善)

动力节点-crm-项目笔记(待完善)

is是我们new的 out,是respond new的 tomcat关我们就不用关了

File file=new File("D:\\Desktop\\word文档\\",originalFilename);//路径必须手动创建好,文件如果不存在,会自动创建

public void fileDownload(HttpServletResponse response) throws Exception{
    //1.设置响应类型
    response.setContentType("application/octet-stream;charset=UTF-8");
    //2.获取输出流
    OutputStream out=response.getOutputStream();
    //浏览器接收到响应信息之后,默认情况下,直接在显示窗口中打开响应信息;即使打不开,也会调用应用程序打开;只有实在打不开,才会激活文件下载窗口。
    //可以设置响应头信息,使浏览器接收到响应信息之后,直接激活文件下载窗口,即使能打开也不打开
    response.addHeader("Content-Disposition","attachment;filename=mystudentList.xls");

    //读取excel文件(InputStream),把输出到浏览器(OutoutStream)
    InputStream is=new FileInputStream("D:\\course\\18-CRM\\阶段资料\\serverDir\\studentList.xls");
    byte[] buff=new byte[256];
    int len=0;
    while((len=is.read(buff))!=-1){
        out.write(buff,0,len);
    }
    //关闭资源
    is.close();
    out.flush();
}

//浏览器接收到响应信息之后,默认情况下,直接在显示窗口中打开响应信息;即使打不开,也会调用应用程序打开;只有实在打不开,才会激活文件下载窗口。

//可以设置响应头信息,使浏览器接收到响应信息之后,直接激活文件下载窗口,即使能打开也打不开

response.addHeader("Content-Disposition","attachment;filename=mystudentList.xls");

attachment 附件

10.1.3 表单的编码格式只能用:multipart/form-data

<form action="workbench/activity/fileUpload.do" method="post" enctype="multipart/form-data">
  <input type="file" name="myFile"><br>
  <input type="text" name="userName"><br>
  <input type="submit" value="提交">
</form>

根据HTTP协议的规定,浏览器每次向后台提交参数,都会对参数进行统一编码;默认采用的编码格式是entype= "urlencoded",这种编码格式只能对文本数据进行编码;

浏览器每次向后台提交参数,都会首先把所有的参数转换成字符串,然后对这些数据统一进行urlencoded编码;对服务器传来的数据也通过这种方式进行解码 以前的提交的参数传输可以这么做,现在要传输文件了(传输二进制)就不能用这种编码方式

文件上传的表单编码格式只能用multipart/form-data:enctype="multipart/form-data" 功能:只是阻止默认行为

在循环体外面创建对象,提高效率 Activity activity=null;

if (activityList.size()>0&&activityList!=null){
    Activity activity=null;
    for (int i = 0; i < activityList.size(); i++) {
    //    Activity  activity = activityList.get(i);
        activity = activityList.get(i);
        //sheet.createRow(i+1);
        row=sheet.createRow(i+1);

访问磁盘的效率是最低的,访问磁盘效率低尽量少访问,尽量多访问内存

wb.write(out) 将wb的内存数据放入out中然后,通过respond响应管道到前端

10.2 导入市场活动:

10.2.1 文件导入ajax的异步请求

//给"导入"按钮添加单击事件
$("#importActivityBtn").click(function () {
    //收集参数
    var activityFileName=$("#activityFile").val();
    var suffix=activityFileName.substr(activityFileName.lastIndexOf(".")+1).toLocaleLowerCase();//xls,XLS,Xls,xLs,....
    if(suffix!="xls"){
        alert("只支持xls文件");
        return;
    }
    var activityFile=$("#activityFile")[0].files[0];
    if(activityFile.size>5*1024*1024){
        alert("文件大小不超过5MB");
        return;
    }

    //FormData是ajax提供的接口,可以模拟键值对向后台提交参数;
    //FormData最大的优势是不但能提交文本数据,还能提交二进制数据
    var formData=new FormData();
    formData.append("activityFile",activityFile);
    formData.append("userName","张三");

    //发送请求
    $.ajax({
        url:'workbench/activity/importActivity.do',
        data:formData,
        processData:false,//设置ajax向后台提交参数之前,是否把参数统一转换成字符串:true--是,false--不是,默认是true
        contentType:false,//设置ajax向后台提交参数之前,是否把所有的参数统一按urlencoded编码:true--是,false--不是,默认是true
        type:'post',
        dataType:'json',
        success:function (data) {
            if(data.code=="1"){
                //提示成功导入记录条数
                alert("成功导入"+data.message+"条记录");
                //关闭模态窗口
                $("#importActivityModal").modal("hide");
                //刷新市场活动列表,显示第一页数据,保持每页显示条数不变
                queryActivityByConditionForPage(1,$("#demo_pag1").bs_pagination('getOption', 'rowsPerPage'));
            }else{
                //提示信息
                alert(data.message);
                //模态窗口不关闭
                $("#importActivityModal").modal("show");
            }
        }
    });
});
@RequestMapping("/workbench/activity/importActivity.do")
@ResponseBody
public Object importActivity(MultipartFile activityFile,HttpSession session){
    User user = (User) session.getAttribute(Contants.SESSION_USER);
    List<Activity> activityList=new ArrayList<>();
    ReturnObject returnObject = new ReturnObject();

    try {
        /*String originalFilename = activityFile.getOriginalFilename();
        File file = new File("D:\\Desktop\\word文档\\",originalFilename);
        activityFile.transferTo(file);


        FileInputStream fileInputStream = new FileInputStream("D:\\Desktop\\word文档\\"+originalFilename);*/

        //增加
        InputStream inputStream = activityFile.getInputStream();

        HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
        HSSFSheet sheet = workbook.getSheetAt(0);
        Activity activity=null;
        HSSFRow row =null;
        HSSFCell cell =null;
        for (int i = 1; i <= sheet.getLastRowNum() ; i++) {
            row = sheet.getRow(i);

            activity=new Activity();
            activity.setId(UUIDUtils.getUUID());
            activity.setOwner(user.getId());
            for (int j = 0; j < row.getLastCellNum(); j++) {

                cell = row.getCell(j);
                String cellValue = HSSFUtils.getCellValueForStr(cell);
                if(j==0){
                    activity.setName(cellValue);
                }else if(j==1){
                    activity.setStartDate(cellValue);
                }else if(j==2){
                    activity.setEndDate(cellValue);
                }else if(j==3){
                    activity.setCost(cellValue);
                }else if(j==4){
                    activity.setDescription(cellValue);
                }
            }
            activityList.add(activity);
        }

        int i = activityService.saveMultipleActivity(activityList);


        returnObject.setMessage("成功插入"+i+"数据");
        returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);
    } catch (IOException e) {
        returnObject.setMessage("插入失败");
        returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
        e.printStackTrace();
    }
    return returnObject;
}

10.2.2 flush方法

为了提高IO吞吐效率,一般的IO服务都带缓冲区,当缓冲区满了再输出一次,这样减少IO次数。

flush() 则要求立即将缓冲区的数据输出到接收方。

在java开发中,有时我们会进行流的操作,所以可能会经常遇到这样一段代码

out.flush();
out.close();

有时我们只是大概看懂这些,却不知道其中的原理性东西,下面就来理解一下:
flush()这个函数是清空的意思,用于清空缓冲区的数据流,进行流的操作时,数据先被读到内存中,然后再用数据写到文件中,那么当你数据读完时,我们如果这时调用close()方法关闭读写流,这时就可能造成数据丢失,为什么呢,因为,读入数据完成时不代表写入数据完成,一部分数据可能会留在缓存区中,为了理解这个问题,我们举一个例子:

比如,在农村,几乎每家都有抽水机,抽水机的作用是什么呢,就是把水井里的水抽到水缸中,这时我们就会用水管连接抽水机和水缸(水管就好比是缓冲区),当我们想把水井中的水都抽到水缸中时,我们就让抽水机工作抽水,如果我们发现水井里的水刚好抽完时,我们就会关掉抽水机的开关停止抽水,那么这时,管道里就会遗留一部分水,抽水就是读数据,水缸进水就是写数据,水管充当缓存区的角色,不知道这样是不是具象化了呢

那么这样一来我们如果中途调用close()方法,输出区也还是有数据的,就像水缸里有水,只是在缓冲区遗留了一部分,这时如果我们先调用flush()方法,就会强制把数据输出,缓存区就清空了,最后再关闭读写流调用close()就完成了。

10.2.3 MultipartFile myFile

前端,传参数myFile

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n3cIqwt0-1652762340017)(C:/Users/86199/AppData/Roaming/Typora/typora-user-images/image-20220513152000643.png)]

把post请求体中所有的数据封装到 参数myFile中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nJFOZVjB-1652762340019)(C:/Users/86199/AppData/Roaming/Typora/typora-user-images/image-20220513151919584.png)]

调用这个 类 然后参数从 请求体中拿数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QfewWJnO-1652762340022)(C:/Users/86199/AppData/Roaming/Typora/typora-user-images/image-20220513152320814.png)]

必须配置这个类 接受到文件上传请求后自动调用这个类

配置文件上传解析器 id:必须是multipartResolver 要不然会找不到

动力节点-crm-项目笔记(待完善)

11. web

11.0.1 post和get详解

文件上传的表单三个条件:
1.表单组件标签必须用:

<input type="file">
      <input type="text|password|radio|checkbox|hidden|button|submit|reset|file">
                   <select>,<textarea>

​ 2.请求方式只能用:post
​ get:参数通过请求头提交到后台,参数放在URL后边;只能向后台提交文本数据;对参数长度有限制;数据不安全;效率高
​ post:参数通过请求体提交到后台;既能能提交文件数据,又能够提交二进制数据;理论上对参数长度没有限制;相对安全;效率相对较低

get效率高,因为get能使用缓存将静态页面,图片缓存起来 post只能一个个向后端请求 重新传一遍无法进行缓存,

get因为有缓存,改静态页面要清理缓存才有效果,所以get对开发不友好

所以开发时能用post就用post

get长度有限制是因为 浏览器对地址栏长度有限制,所以对get参数有限制

11.0.2 web中的同步和异步:

(1)同步请求:顺序处理,即当我们向服务器发出一个请求时,在服务器没返回结果给客户端之前,我们要一直处于等待状态直至服务器将结果返回到客户端,我们才能执行下一步操作。例如普通的B/S模式就是同步请求(注:B/S模式 也即服务器与浏览器通信主要采用HTTP协议;通信方式为“请求——响应”,浏览器发出请求;服务器做出响应。)
(2)异步请求:并行处理,当我们向服务器发出一个请求时,在服务器没返回结果之前,我们还是可以执行其他操作。例如AJAX技术就是异步请求。

同步请求一般返回一个网页,异步请求一般返回一个data数据

同步请求不要返回json因为解析不了

看同步还是异步看是否会刷新整个页面

在循环体外加一个变量

?ClueActivityRelation clueActivityRelation=null; 加一个变量效率更高

ClueActivityRelation clueActivityRelation=null;
for (int i = 0; i < activityId.length; i++) {
    clueActivityRelation = new ClueActivityRelation();
    clueActivityRelation.setId(UUIDUtils.getUUID());
    clueActivityRelation.setActivityId(activityId[i]);
    clueActivityRelation.setClueId(clueId);
    clueActivityRelationList.add(clueActivityRelation);

}

j1){
activity.setStartDate(cellValue);
}else if(j
2){
activity.setEndDate(cellValue);
}else if(j3){
activity.setCost(cellValue);
}else if(j
4){
activity.setDescription(cellValue);
}
}
activityList.add(activity);
}

    int i = activityService.saveMultipleActivity(activityList);


    returnObject.setMessage("成功插入"+i+"数据");
    returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);
} catch (IOException e) {
    returnObject.setMessage("插入失败");
    returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
    e.printStackTrace();
}
return returnObject;

}


#### 10.2.2    flush方法



> 为了提高IO吞吐效率,一般的IO服务都带缓冲区,当缓冲区满了再输出一次,这样减少IO次数。

 

flush() 则要求立即将缓冲区的数据输出到接收方。

在java开发中,有时我们会进行流的操作,所以可能会经常遇到这样一段代码

out.flush();
out.close();

有时我们只是大概看懂这些,却不知道其中的原理性东西,下面就来理解一下:
flush()这个函数是清空的意思,用于清空缓冲区的数据流,进行流的操作时,数据先被读到内存中,然后再用数据写到文件中,那么当你数据读完时,我们如果这时调用close()方法关闭读写流,这时就可能造成数据丢失,为什么呢,因为,读入数据完成时不代表写入数据完成,一部分数据可能会留在缓存区中,为了理解这个问题,我们举一个例子:

比如,在农村,几乎每家都有抽水机,抽水机的作用是什么呢,就是把水井里的水抽到水缸中,这时我们就会用水管连接抽水机和水缸(水管就好比是缓冲区),当我们想把水井中的水都抽到水缸中时,我们就让抽水机工作抽水,如果我们发现水井里的水刚好抽完时,我们就会关掉抽水机的开关停止抽水,那么这时,管道里就会遗留一部分水,抽水就是读数据,水缸进水就是写数据,水管充当缓存区的角色,不知道这样是不是具象化了呢

那么这样一来我们如果中途调用close()方法,输出区也还是有数据的,就像水缸里有水,只是在缓冲区遗留了一部分,这时如果我们先调用flush()方法,就会强制把数据输出,缓存区就清空了,最后再关闭读写流调用close()就完成了。




#### 10.2.3      MultipartFile myFile

前端,传参数myFile

[外链图片转存中...(img-n3cIqwt0-1652762340017)]



把post请求体中所有的数据封装到 参数myFile中

[外链图片转存中...(img-nJFOZVjB-1652762340019)]



调用这个  类   然后参数从 请求体中拿数据   

[外链图片转存中...(img-QfewWJnO-1652762340022)]

必须配置这个类   接受到文件上传请求后自动调用这个类



 配置文件上传解析器 id:必须是multipartResolver  要不然会找不到

[外链图片转存中...(img-xDWy5S8Y-1652762340025)]





## 11.     web

#### 11.0.1    post和get详解



 文件上传的表单三个条件:
    1.表单组件标签必须用:

```html
<input type="file">
      <input type="text|password|radio|checkbox|hidden|button|submit|reset|file">
                   <select>,<textarea>等

​ 2.请求方式只能用:post
​ get:参数通过请求头提交到后台,参数放在URL后边;只能向后台提交文本数据;对参数长度有限制;数据不安全;效率高
​ post:参数通过请求体提交到后台;既能能提交文件数据,又能够提交二进制数据;理论上对参数长度没有限制;相对安全;效率相对较低

get效率高,因为get能使用缓存将静态页面,图片缓存起来 post只能一个个向后端请求 重新传一遍无法进行缓存,

get因为有缓存,改静态页面要清理缓存才有效果,所以get对开发不友好

所以开发时能用post就用post

get长度有限制是因为 浏览器对地址栏长度有限制,所以对get参数有限制

11.0.2 web中的同步和异步:

(1)同步请求:顺序处理,即当我们向服务器发出一个请求时,在服务器没返回结果给客户端之前,我们要一直处于等待状态直至服务器将结果返回到客户端,我们才能执行下一步操作。例如普通的B/S模式就是同步请求(注:B/S模式 也即服务器与浏览器通信主要采用HTTP协议;通信方式为“请求——响应”,浏览器发出请求;服务器做出响应。)
(2)异步请求:并行处理,当我们向服务器发出一个请求时,在服务器没返回结果之前,我们还是可以执行其他操作。例如AJAX技术就是异步请求。

同步请求一般返回一个网页,异步请求一般返回一个data数据

同步请求不要返回json因为解析不了

看同步还是异步看是否会刷新整个页面

在循环体外加一个变量

?ClueActivityRelation clueActivityRelation=null; 加一个变量效率更高

ClueActivityRelation clueActivityRelation=null;
for (int i = 0; i < activityId.length; i++) {
    clueActivityRelation = new ClueActivityRelation();
    clueActivityRelation.setId(UUIDUtils.getUUID());
    clueActivityRelation.setActivityId(activityId[i]);
    clueActivityRelation.setClueId(clueId);
    clueActivityRelationList.add(clueActivityRelation);

}

版权声明:程序员胖胖胖虎阿 发表于 2022年10月3日 上午8:40。
转载请注明:动力节点-crm-项目笔记(待完善) | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...