CRM项目(SSM)总结 byYOnGKAnG
目录
1.配置字符集,和配置文件(properties、xml)文件中的字符集,编译器、项目字符集,静态资源字符集统一设置成utf-8字符集
2.设置web项目(前提是没有使用maven),由于做项目的时候使用maven快捷搭建项目加载不出来。
applicationContext-datasource.xml
2)修改功能,点击修改会将所点击的记录对应数据显示在文本框中
3)删除功能,可以同时删除多条记录,ajax三种向后台提交数据的方式
1)根据前端传给后端的键,通过properties获取对应的值
3)mapper.xml中传入参数不能同时传入两个对象,多个数据需要使用实体类或集合传递
6.配置tomact时没有可用的工件以及tomact访问路径问题
一.搭建环境
1.配置字符集,和配置文件(properties、xml)文件中的字符集,编译器、项目字符集,静态资源字符集统一设置成utf-8字符集
![](https://i-blog.csdnimg.cn/blog_migrate/c78224c52391aaa0fab17c09f21aabc0.png)
2.设置web项目(前提是没有使用maven),由于做项目的时候使用maven快捷搭建项目加载不出来。
在file->project structure选项卡moudle中点击‘+’号添加web项目
3.配置maven,pom文件
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.zhai</groupId>
<artifactId>crm</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>crm Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.15.RELEASE</version>
</dependency>
<!-- MySQL数据库连接驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.43</version>
</dependency>
<!-- JDBC数据源连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.1</version>
</dependency>
<!-- MyBatis框架依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<!-- Spring框架依赖的JAR配置 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<!-- Spring AOP支持-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!-- MyBatis与Spring整合依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- servlet及jstl标签库依赖的JAR配置 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-spec</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.1</version>
</dependency>
<!-- 加载jackson插件依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.7.3</version>
</dependency>
<!--poi依赖-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.15</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Log4j2依赖的JAR配置 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
<finalName>crm</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
4.配置spring、springmvc、mybatis配置文件
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--命名空间-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 加载系统配置文件
<context:property-placeholder location="classpath:*.properties" />-->
<!-- 扫描注解 -->
<context:component-scan base-package="com.bjpowernode.crm.settings.service" />
<context:component-scan base-package="com.bjpowernode.crm.workbench.service"/>
<context:component-scan base-package="com.bjpowernode.crm.zhaiyongkang.service"/>
<!-- 导入数据相关配置 -->
<import resource="applicationContext-datasource.xml" />
</beans>
applicationContext-datasource.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/crm?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
</bean>
<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 必须注入属性dataSource -->
<property name="dataSource" ref="dataSource"/>
<!-- 如果mybatis没有特殊的配置(比如别名等),configLocation可以省去 ;否则,不能省略-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- mapper注解扫描器配置,扫描@MapperScan注解,自动生成代码对象 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.bjpowernode.crm.settings.mapper
com.bjpowernode.crm.workbench.mapper
com.bjpowernode.crm.zhaiyongkang.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务 -->
<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>
</beans>
applicationContext-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- dispatcherServlet截获所有URL请求 -->
<mvc:default-servlet-handler />
<!-- spring mvc 扫描包下的controller -->
<context:component-scan base-package="com.bjpowernode.crm.web.controller"/>
<context:component-scan base-package="com.bjpowernode.crm.settings.web.controller"/>
<context:component-scan base-package="com.bjpowernode.crm.workbench.web.controller"/>
<context:component-scan base-package="com.bjpowernode.crm.zhaiyongkang.controller"/>
<!-- 配置注解驱动 -->
<mvc:annotation-driven/>
<!-- 配置视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截url还有controller,因为我们controller url起名的时候和资源路径一致-->
<!-- /settings/*代表settings下的一层子目录,/settings/**代表settings下子目录下多层子目录-->
<mvc:mapping path="/settings/**"/>
<mvc:mapping path="/workbench/**"/>
<!-- 为登录页面放行-->
<mvc:exclude-mapping path="/settings/qx/user/login.do"/>
<mvc:exclude-mapping path="/settings/qx/user/toLogin.do"/>
<bean class="com.bjpowernode.crm.settings.web.interceptor.LoginInteceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<!-- 配置文件上传解析器 id:必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="#{1024*1024*80}"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>
</beans>
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!-- 别名-->
<typeAliases>
<package name="com.bjpowernode.crm.model"/>
</typeAliases>
<mappers>
<package name="com.bjpowernode.crm.mapper"/>
</mappers>
</configuration>
二.编码实现
1.用户登录
功能:免登录,十天内免登录
代码:UserConroller、UserService、UserServiceImpl、UserMapper、UserMapper.xml
主要部分:
1)十天内免登录
@RequestMapping("/settings/qx/user/login.do")
public @ResponseBody Object login(String loginAct, String loginPwd, String isRemPwd, HttpServletRequest request, HttpSession session, HttpServletResponse response){
Map<String,Object> map=new HashMap<>();
map.put("loginAct",loginAct);
map.put("loginPwd",loginPwd);
User user = userService.queryUserByLoginActAndPwd(map);
ReturnObject returnObject=new ReturnObject();
if (user==null){
//登录失败
returnObject.setCode("0");
returnObject.setMessage("用户民或密码错误");
}else{//判断时间是否过期
if (DateUtils.formateDateTime(new Date()).compareTo(user.getExpireTime())>0){
//账号过期
returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
returnObject.setMessage("账号过期");
}else if("0".equals(user.getLockState())){
//账号被锁定
returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
returnObject.setMessage("账号被锁定");
}else if(!user.getAllowIps().contains(request.getRemoteAddr())){
//检查ip
returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
returnObject.setMessage("IP受限");
}else{
returnObject.setCode(Contants.RETURN_OBJECT_CODE_SUCCESS);
session.setAttribute("sessionUser",user);
}
}
//如果用户选择十天内记住密码,则往浏览器写cookie
if ("true".equals(isRemPwd)){
Cookie c1=new Cookie("loginAct",loginAct);
c1.setMaxAge(10*24*60*60);
response.addCookie(c1);
Cookie c2=new Cookie("loginPwd",loginPwd);
c2.setMaxAge(10*24*60*60);
response.addCookie(c2);
}else{
/**
* 如果用户没有点击或取消十天内记住密码,则利用浏览器kill cookie,
* 也就是将cookie的寿命设置为0,
* 设置同名cookie可以将原有cookie的属性覆盖包括生命周期
*/
Cookie c1=new Cookie("loginAct","1");
c1.setMaxAge(0);
response.addCookie(c1);
Cookie c2=new Cookie("loginPwd","2");
c2.setMaxAge(0);
response.addCookie(c2);
}
return returnObject;
}
描述:方法接受来自前端的账号和密码封装成map,将map参数传给UserService、service调用mapper,通过账号和密码查询user,返回一个user对象,如果数据库中没有符合条件的,user则为空,则登录失败,如果不为空则依次判定条件,直到最后条件都满足,则把user对象放入session,然后判断、用户是否选择了记住密码,选择了就创建cookie通过response传给客户端本地保存,用户再次访问页面,会将本地cookie取出判断是否为空
<form action="workbench/index.html" class="form-horizontal" role="form">
<div class="form-group form-group-lg">
<div style="width: 350px;">
<input class="form-control" type="text" placeholder="用户名" id="loginAct" value="${cookie.loginAct.value}">
</div>
<div style="width: 350px; position: relative;top: 20px;">
<input class="form-control" type="password" placeholder="密码" id="loginPwd" value="${cookie.loginPwd.value}">
</div>
<div class="checkbox" style="position: relative;top: 30px; left: 10px;">
<%-- 使用jstl标签做判断,如果客户端有cookie且值不为空则复选框是选中的状态否则不是--%>
<label>
<c:if test="${not empty cookie.loginAct.value and not empty cookie.loginPwd.value}">
<input type="checkbox" id="isRemPwd" checked> 十天内免登录
</c:if>
<c:if test="${empty cookie.loginAct.value or empty cookie.loginPwd.value}">
<input type="checkbox" id="isRemPwd"> 十天内免登录
</c:if>
</label>
<span id="msg"></span>
</div>
<button type="button" id="loginBtn" class="btn btn-primary btn-lg btn-block" style="width: 350px; position: relative;top: 45px;">登录</button>
</div>
</form>
cookie中有值则显示,空就显示空,复选框按钮cookie有值就是选中状态,没有则不是选中状态
2.市场活动
功能:分页显示活动条数,创建、修改、删除、表转.xls、xls转表(对应导入导出功能)、下载、模糊查询
代码:ActivityMapper、ActivityMapper.xml、ActivityController、ActivityService、ActivityServiceImpl
主要部分:
1)分页显示和动态显示活动
function queryActivityByConditionForPage(pageNo,pageSize){
//获取四个查询条件文本框的值
var name=$("#query-name").val();
var owner=$("#query-owner").val();
var endDate=$("#query-endDate").val();
var startDate=$("#query-startDate").val();
//发送请求
$.ajax({
url:'workbench/activity/queryActivityConditionForPage.do',
data:{
name:name,
owner:owner,
startDate:startDate,
endDate:endDate,
pageSize:pageSize,
pageNo:pageNo
},
type: 'post',
dataType: 'json',
success:function(data){
// $("#totalRowsB").text(data.totalRows);
var htmlStr="";
htmlStr+="<li>";
htmlStr+="<a href=\"#\" aria-label=\"Previous\">";
htmlStr+="<span aria-hidden=\"true\">«</span>";
htmlStr+="</a>";
htmlStr+="</li>";
for (var i=1;i<=data.yeshu;i++){
htmlStr+="<li><a name=\""+i+"\" onclick=\"findActivity(this.name)\" href=\"javascript:;\">"+i+"</a></li>";
}
htmlStr+="<li>";
htmlStr+="<a href=\"#\" aria-label=\"Next\">";
htmlStr+="<span aria-hidden=\"true\">»</span>";
htmlStr+="</a>";
htmlStr+="</li>";
//.html意思就是指定容器下要显示的html是,而append有追加的意思每一回调用函数都会追加
$("#page-table").html(htmlStr);
var htmlStr="";
$.each(data.activityList,function (index,obj){
htmlStr+="<tr class=\"active\">";//双引号之中不允许再有双引号需要使用转义字符'\'
htmlStr+="<td><input type=\"checkbox\" value=\""+obj.id+"\"/></td>";
//给名称超链接绑定活动id
htmlStr+="<td><a style=\"text-decoration: none; cursor: pointer;\" onclick=\"window.location.href='workbench/activity/detailActivity.do?id="+obj.id+"'\">"+obj.name+"</a></td>";
htmlStr+="<td>"+obj.owner+"</td>";
htmlStr+="<td>"+obj.startDate+"</td>";
htmlStr+="<td>"+obj.endDate+"</td>";
htmlStr+="</tr>";
});
$("#tboday-activity").html(htmlStr);
}
});
描述:这里的pageNo和pageSize是固定的是1和10意思就是默认从第一页查,每一页最多十条记录,同时获取四个查询文本框的值,异步提交给controller,最主要的就是mapper.xml文件中的sql语句使用了动态sql,如果四个条件参数有值则根据条件查询,没值则条件查询不成立,会把全部数据返回
@RequestMapping("/workbench/activity/queryActivityConditionForPage.do")
@ResponseBody
public Object queryActivityConditionForPage(String owner, String name, String startDate, String endDate, @RequestParam(value="pageNo",defaultValue = "1")int pageNo, @RequestParam(value="pageSize",defaultValue="10")int pageSize){
//利用map封装查询条件
Map<String,Object> map=new HashMap();
map.put("name",name);
map.put("owner",owner);
map.put("endDate",endDate);
map.put("startDate",startDate);
map.put("beginNo",(pageNo-1)*pageSize);
map.put("pageSize",pageSize);
//返回查询的记录,如果条件为空会将从pageNo开始pageSize个记录返回到客户端
List<Activity> activityList=activityService.queryActicityByConditionForPage(map);
int totalRows=activityService.queryCountOfActivityCondition(map);//总共记录数,前台会利用总记录数和每页显示条数计算页数
Map<String,Object> retmap=new HashMap<>();//以json格式返回数据
retmap.put("activityList",activityList);
retmap.put("totalRows",totalRows);
int yeshu;//返回页数,能除尽直接返回,除不尽则进行取整操作
if (totalRows%pageSize==0){
yeshu=totalRows/pageSize;
}else {
yeshu=totalRows/pageSize+1;
}
retmap.put("yeshu",yeshu);
return retmap;
}
描述:后台将客户端传来的数据封装成一个map集合,后台对map集合中的值进行修改创建,作为查询条件传给Activitymapper.xml,mysql实现分页是使用limt实现,后台将客户端需要的数据用json格式返回给客户端(就是map集合转成json数据)
前端ajax,success函数中创建动态标签,分别创建了两个动态标签,一个是动态创建分页,一个是将表记录(市场活动)数据动态创建到客户端
动态创建分页标签的时候会把页号绑定到a标签的name属性中,单击对应页号(例如:2)时,会将页号传给函数function findActivity(pageNo)然后再次异步提交给后台,后台根据新的页号再次异步提交,其中pageSize还是固定的10,map.put("beginNo",(pageNo-1)*pageSize);,通过运算实际查询的数据就是查询从第10条记录查,查十条记录返回到客户端
limit #{beginNo},#{pageSize}
意思是将查询到的数据从第beginNo条开始查询pageSize条数据返回
2)修改功能,点击修改会将所点击的记录对应数据显示在文本框中
//修改按钮单击事件
$("#editActivityBtn").click(function (){
var checks=$("#tboday-activity input[type='checkbox']:checked");
if(checks.size()==0){
alert("请选中要修改的数据");
return;
}
if(checks.size()>1){
alert("只能修改一条数据");
return;
}
var id=checks.get(0).value;
$.ajax({
url:'workbench/activity/selectActivityById.do',
data:{
id:id
},
type:'post',
dataType:'json',
success:function (data){
$("#edit-id").val(data.id);
$("#edit-marketActivityOwner").val(data.owner);
$("#edit-marketActivityName").val(data.name);
$("#edit-startTime").val(data.startDate);
$("#edit-endTime").val(data.endDate);
$("#edit-cost").val(data.cost);
$("#edit-describe").val(data.description);
$("#editActivityModal").modal("show");
}
});
});
描述:点击修改按钮会执行依次异步提交,ajax会获取所修改记录的id并传给后端,后端进行查询封装成一个实体类对象返回给客户端ajax,ajax将数据显示在模态窗口中 ,对数据进行修改完之后点击更新按钮,将模态窗口中修改过后的数据异步提交后端,传给mapper,对数据库表进行更新,更新成功够关闭模态窗口
3)删除功能,可以同时删除多条记录,ajax三种向后台提交数据的方式
$("#deleteActivityBtn").click(function (){
//获取参数
//获取所有被选中的复选框
var checks=$("#tboday-activity input[type='checkbox']:checked");
if(checks.size()==0){
alert("请选择要删除的选项");
return;
}
//ajax向后台传数据有三种方式详见笔记,向后台提交数据格式id=xxx&id=xxx
if (window.confirm("确定要删除吗")) {
var ids="";
$.each(checks,function (index,obj){
ids+="id="+this.value+"&";
});
//substr从startIndex截到endIndex
//substring从startIndex截几个字符
ids=ids.substr(0,ids.length-1);
$.ajax({
url:'workbench/activity/deleteByIds.do',
data:ids,
type:'post',
dataType:'json',
success:function (data){
if (data.code=="1"){
alert(data.message);
queryActivityByConditionForPage(1,10);
}else{
alert(data.message);
}
}
});
} else {
}
});
描述:其中最主要的就是ajax向后台提交数据有三种方式,第一种是常用的json形式。第二种就是这种拼接字符串的的形式,在这里,后端需要提供String[]接受客户端传来的参数。第三种就是FormData,FormData是ajax提供的接口(用java的理解js的接口就相当于java类),模拟键值对向后台提交数据 ,它最大的优点就是不仅能向后台提交文本数据,还能提交二进制数据,会在导入功能中使用,实现将文件传递给后端
<delete id="deleteByIds" parameterType="string">
delete from tbl_activity where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
其中mapper.xml文件解析字符数组用到了foreach循环遍历 ,collection参数可以是list、array
4)上传列表数据功能,将xls转为 java数据
@RequestMapping("/workbench/activity/saveActivityByList.do")
@ResponseBody
public Object saveActivityByList(MultipartFile activityFile,HttpSession session,String userName){
ReturnObject returnObject=new ReturnObject();
System.out.println(userName);
try {
String originalFilename = activityFile.getOriginalFilename();
User user=(User)session.getAttribute(Contants.SESSION_USER);
InputStream inputStream = activityFile.getInputStream();
HSSFWorkbook hw=new HSSFWorkbook(inputStream);
HSSFSheet sheet=hw.getSheetAt(0);
HSSFRow row=null;
HSSFCell cell=null;
Activity activity=null;
List<Activity> list=new ArrayList<>();
for (int i=1;i<=sheet.getLastRowNum();i++){
row=sheet.getRow(i);
activity=new Activity();
activity.setId(UUIDUtils.getUUID());
activity.setOwner(user.getId());
activity.setCreateTime(DateUtils.formateDateTime(new Date()));
activity.setCreateBy(user.getId());
String cellValue;
for (int j=0;j<row.getLastCellNum();j++) {
cell = row.getCell(j);
if (cell!=null) {
cellValue = USSFUUtils.getCellValueForStr(cell);
}else{
cellValue="";
}
if (j == 0) {
activity.setName(user.getName());
} 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);
}
}
list.add(activity);
}
//调用service方法
int i = activityService.saveActivityByList(list);
returnObject.setMessage("输入"+i+"条记录");
} catch (IOException e) {
e.printStackTrace();
returnObject.setCode(Contants.RETURN_OBJECT_CODE_FAIL);
returnObject.setMessage("系统der了");
}
return returnObject;
}
package com.bjpowernode.crm.commons.utils;
import org.apache.poi.hssf.usermodel.HSSFCell;
public class USSFUUtils {
public static String getCellValueForStr(HSSFCell cell) {
String ret = "";
if (cell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
ret = cell.getStringCellValue();
} else if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {
ret = cell.getNumericCellValue() + "";
} else if (cell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) {
ret = cell.getBooleanCellValue() + "";
} else if (cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
ret = cell.getCellFormula();
} else {
ret = "";
}
return ret;
}
}
描述:这里用到了poi插件,最主要的是提供了HSSFWorkbook对象,还有自定义的工具类,会将从xls文件中获取的数据自动转为字符串,Row行,Cell列
5)导出,下载功能,java转xls
@RequestMapping("/workbench/activity/exportAllActivitys")
public void exportAllActivitys(HttpServletResponse response)throws Exception{
List<Activity> list=activityService.selectAllActivity();
HSSFWorkbook hw=new HSSFWorkbook();
if (list!=null&&list.size()!=0){
HSSFSheet sheet=hw.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("修改者");
//遍历list
for (int i=0;i<list.size();i++){
Activity activity=list.get(i);
//每遍历出一条记录,都往对应坐标的单元格写数据
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());
}
// hw.write(fileOutputStream);
// //关闭资源
// fileOutputStream.close();
}
// FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\翟永康\\OneDrive\\桌面\\img\\activity.xls");
//设置响应数据类型
response.setContentType("application/octet-stream;charset=utf-8");
OutputStream out=response.getOutputStream();
//设置响应头信息,客户端收到响应信息之后,直接激活文件下载窗口,即使能打开也不打开,filename是附加参数意为文件名还能加时间戳
response.addHeader("Content-Disposition","attachment;filename=activity.xls");
// InputStream in=new FileInputStream(new File("C:\\Users\\翟永康\\OneDrive\\桌面\\img\\activity.xls"));
// byte [] buff=new byte[256];//缓冲区,如果不用缓冲区默认每回读一个字节效率低
// int len=0;
// while((len=in.read(buff))!=-1){
// out.write(buff,0,len);
// }
hw.write(out);
//关闭资源,关闭自己new的资源outputstream是tomact,new的tomact管它
//刷新流
hw.close();
out.flush();
}
描述:还是使用poi插件对HSSFWorkbook对象进行操作Row行,Cell列,实现下载功能,需要设置响应数据类型,响应头信息,使用poi插件的write方法将返回给浏览器
3.市场活动细节
主要功能:显示市场活动细节,有备注
代码:ActivityRemark、ActivityRemarkMapper、ActivityRemarkMapper.xml、ActivityService、ActivityServiceMap
主要部分:
1)备注,对动态标签添加事件
//备注保存按钮添加单击事件
$("#saveActivityRemarkBtn").click(function (){
var activityId='${activity.id}';
var noteContent=$.trim($("#remark").val());
$("#remarkForm").get(0).reset();//清空表单,添加备注清楚文本框的效果。得在获取值之后清空
if (noteContent==""){
alert("内容不能为空");
return;
}
$.ajax({
url:'workbench/activity/saveCreateActivityRemark.do',
data:{
noteContent:noteContent,
activityId:activityId
},
type:'post',
dataType:'json',
success:function (data){
if (data.code=="1"){
var htmlstr="";
htmlstr+="<div class=\"remarkDiv\" id=\"div_"+data.retData.id+"\" style=\"height: 60px;\">";
htmlstr+="<img title=\"${sessionScope.sessionUser.name}\" src=\"image/user-thumbnail.png\" style=\"width: 30px; height:30px;\">";
htmlstr+="<div style=\"position: relative; top: -40px; left: 40px;\" >";
htmlstr+="<h5>"+noteContent+"</h5>";
htmlstr+="<font color=\"gray\">市场活动</font> <font color=\"gray\">-</font> <b>${activity.name}</b> <small style=\"color: gray;\"> "+data.retData.createTime+" 由${sessionScope.sessionUser.name}创建</small>";
htmlstr+="<div style=\"position: relative; left: 500px; top: -30px; height: 30px; width: 100px; display: none;\">";
htmlstr+="<a class=\"myHref myHrefEdit\" remarkId=\"${remark.id}\" href=\"javascript:void(0);\"><span class=\"glyphicon glyphicon-edit\" style=\"font-size: 20px; color: #E6E6E6;\"></span></a>";
htmlstr+=" ";
htmlstr+="<a class=\"myHref myHrefRemove\" remarkId=\"${remark.id}\" href=\"javascript:void(0);\"><span class=\"glyphicon glyphicon-remove\" style=\"font-size: 20px; color: #E6E6E6;\"></span></a>"
htmlstr+="</div>";
htmlstr+="</div>";
htmlstr+="</div>";
$("#remarkDiv").before(htmlstr);
}else{
alert(data.message);
}
}
});
});
描述:把页面片段动态显示在网页中
还有一个就是上面的$("#remarkDiv").before(htmlstr);,根据使用场景选择,其中生成的是动态标签,动态标签的事件(如jQuery click)和固定标签的事件是不一样的,需要用到父选择器.on("事件","子选择器",function(){});
$("#disableRemark").on("mouseover",".remarkDiv",function (){
$(this).children("div").children("div").show();
});
$("#disableRemark").on("mouseout",".remarkDiv",function (){
$(this).children("div").children("div").hide();
});
//备注修改和删除按钮的css样式改变
$("#disableRemark").on("mouseover",".myHref",function (){
$(this).children("span").css("color","red");
});
$("#disableRemark").on("mouseout",".myHref",function (){
$(this).children("span").css("color","#E6E6E6");
});
上边就是对动态标签添加事件的例子,其中父选择器必须是固定标签,父选择器范围越小越好
4.交易
主要功能:在创建交易的时候使用了自动补全插件,还有与properties文件键值绑定
代码:TranController、TranService、TranServiceImpl、TransactionMapper.xml、TransactionMapper
主要部分
1)根据前端传给后端的键,通过properties获取对应的值
@RequestMapping("/workbench/transaction/getPossibiltyByStage.do")
@ResponseBody
public Object getPossibiltyByStage(String stage){
//resources就是根目录,遍历properties文件
ResourceBundle possibilty = ResourceBundle.getBundle("possibilty");
String ret = possibilty.getString(stage);
return ret;
}
使用ResourceBundle获取名为possibilty的properties文件,其中properties配置文件的特点就是数据是以键值的形式存放的
$("#create-transactionStage").change(function (){
// var stage=$(this).find("option:selected").text();
var stage=$("#create-transactionStage option:selected").text();//这是第二种上面是第一种
$.ajax({
url:'workbench/transaction/getPossibiltyByStage.do',
data:{
stage:stage
},
type:'post',
dataType:'json',
success:function (data){
$("#create-possibility").val(data);
}
});
});
描述:下拉列表框发生改变就会获取所选选项中的文本值var stage=$("#create-transactionStage option:selected").text();这是第二种上面是第一种,获取文本值发送到后端,作为键查询properties中所对应的值返回给前端显示在可能性文本框中
2)自动补全功能
$("#create-accountName").keyup(function (){
//自动补全动态获取数据
$("#create-accountName").typeahead({
source:function (jquery,process){//process里的数据格式是['xxx','xxxxx'...]
$.ajax({
url:'workbench/transaction/queryAllCustomerName.do',
data:{
customerName:jquery
},
type:'post',
dataType:'json',
success:function (data){//['xxx','xxxxx'...]
process(data);
}
});
}
});
});
描述:jquery中存放的是id值为create-accountName的文本框中的值,ajax将文本框中的值传给后端,后端进行模糊查询将返回的数据传递给客户端,通过process(data)将返回的数据在客户端上显示
三.其他
1.关于配置文件
1)properties配置文件:
key1=value1
key2=value2
key3=value3
...
几乎没有冗余数据,效率高,解析相对简单:properties、BundleResource
2)xml配置文件:标签语言
适合配置复杂数据,产生冗余数据,效率低,解析相对复杂:dom4j、jdom
2.后端向前端发送实体类,集合问题
例如在crm项目中
如果在returnobject.setRetData(Object object)中存入的是实体类,那么前端ajax成功返回函数中直接调用data.retData.id,或者其他属性就可以
但是存放的是集合数据,那么就需要$.each(data.retData,function(index.obj){});来遍历集中的集合数据在遍历函数中使用obj.id来获取值
3.关于idea报sql语句错误
1)发现错误日志,sql语句短缺
如customer_id=u,其实应该是customer_id=u1,但实际上mapper.xml文件中sql语句中响应位置并没有短缺,这里其实是因为sql语句有错误并不是误报
2)语句没错但结果为空
如果使用了内外连接则大概率就是因为连接出了问题
3)mapper.xml中传入参数不能同时传入两个对象,多个数据需要使用实体类或集合传递
4.给标签添加属性
1)使用标签保存数据,以便在需要的时候能够获取到这些数据
给标签添加属性:如果是表单组件标签,优先使用value属性,只有value不方便使用时,
如果不是表单组件标签,不推荐使用value,推荐使用自定义属性
2)获取属性值时:如果获取表单组件标签的value属性值:
dom对象.value
jquery对象.val()
如果自定义的属性,不管是什么标签,只能用:jquery对象.attr("属性名");
5.物理模型设计(表)
1)关于主键设置(大部分为id)
在数据库中如果有一组字段能够唯一确定一条记录的,则可以把他设计成表的主键,推荐使用没有业务含义的字段做主键,比如id
主键值的生成方式有自增、自己通过代码逻辑添加(hi/low、uuid、雪花算法)、还有共享主键、联合主键,其中主键生成方式效率最低的就是自增方式,因为它需要在每次添加记录的时候查询mysql内部一个表获取字段值
6.配置tomact时没有可用的工件以及tomact访问路径问题
在File选项卡下project structure Artifacts下设置添加工件,在modules下配置web.xml路径和web resource路径,有时候tomact启动会提示classnotfounder如java.lang.ClassNotFoundException:org.springframework.web.context.ContextLoaderListener
此时就要检查
lib下有没有需要的jar包