BOS2.0业务逻辑
-第二阶段
13.✔★angularJS点击按钮,校验手机,发送验证码
一.页面导入angular.js在div应用模块和控制器
二.对页面获取验证码按钮,添加click事件
三.编写控制器,事件方法代码
<script type="text/javascript">
// 模块定义
var signupApp = angular.module("signupApp", []);
// 控制器定义
signupApp.controller("signupCtrl", ["$scope","$http",function($scope,$http) {
$scope.btnMsg = "发送验证码";
var active = true;
var second = 60; // 倒计时60秒
var secondInterval;
$scope.getCheckCode = function(telephone) {
if(active == false) {
return;
}
// 1 发送一个HTTP请求,通知服务器 发送短信给目标用户
var regex = /^1(3|5|7|8)\d{9}$/;
if(regex.test(telephone)) {
// 校验通过
$http({
method: 'GET',
url: 'customer_sendSms.action',
params : {
telephone : telephone
}
}).error(function(data, status, headers, config) {
// 当响应以错误状态返回时调用
alert("发送短信出错,请联系管理员");
});
} else {
// 校验失败
alert("手机号非法,请重新输入 ");
return;
}
// 2 显示倒计时按钮,60秒后,允许重新发送
active = false;
secondInterval = setInterval(function() {
if(second < 0) {
// 倒计时结束,允许重新发送
$scope.btnMsg = "重发验证码";
// 强制更新视图
$scope.$digest();
active = true;
second = 60;
// 关闭定时器
clearInterval(secondInterval);
secondInterval = undefined;
} else {
// 继续计时
$scope.btnMsg = second + "秒后重发";
// 强制更新视图
$scope.$digest();
second--;
}
}, 1000);
}
}]);
</script>
14.发送短信验证码
一.查看接口服务
二.整合案例代码,编写SmsUtils工具类
ublic class SmsUtils {
private static String userid = "写你申请的用户名";
private static String pass = "密码";
/**
* 调用HTTP 协议方式发送短信
*
* @param mobile
* @param content
* @return
* @throws UnsupportedEncodingException
*/
public static String sendSmsByHTTP(String mobile, String content)
throws UnsupportedEncodingException {
HttpURLConnection httpconn = null;
String result = "Error";
StringBuilder sb = new StringBuilder();
sb.append("http://service.winic.org:8009/sys_port/gateway/index.asp?");
// 以下是参数
sb.append("id=").append(URLEncoder.encode(userid, "gb2312"));
sb.append("&pwd=").append(pass);
sb.append("&to=").append(mobile);
sb.append("&content=").append(URLEncoder.encode(content, "gb2312"));
sb.append("&time=").append("");
try {
URL url = new URL(sb.toString());
httpconn = (HttpURLConnection) url.openConnection();
BufferedReader rd = new BufferedReader(new InputStreamReader(
httpconn.getInputStream()));
result = rd.readLine();
rd.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpconn != null) {
httpconn.disconnect();
httpconn = null;
}
}
return result;
}
/**
* 调用 WebService 协议方式发送短信
*
* @param mobiles
* @param msg
* @return
*/
public static String sendSmsByWebService(String mobiles, String msg) {
String result = "-12";
try {
Document doc;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
InputStream is = getSoapInputStream(userid, pass, mobiles, msg, "");
if (is != null) {
doc = db.parse(is);
NodeList nl = doc.getElementsByTagName("SendMessagesResult");
Node n = nl.item(0);
result = n.getFirstChild().getNodeValue();
is.close();
}
return result;
} catch (Exception e) {
System.out.print("SmsSoap.sendSms error:" + e.getMessage());
return "-12";
}
}
private static String getSoapSmssend(String userid, String pass,
String mobiles, String msg, String time) {
try {
String soap = "";
soap = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+ "<soap:Body>"
+ "<SendMessages xmlns=\"http://tempuri.org/\">" + "<uid>"
+ userid + "</uid>" + "<pwd>" + pass + "</pwd>" + "<tos>"
+ mobiles + "</tos>" + "<msg>" + msg + "</msg>" + "<otime>"
+ time + "</otime>" + "</SendMessages>" + "</soap:Body>"
+ "</soap:Envelope>";
return soap;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
private static InputStream getSoapInputStream(String userid, String pass,
String mobiles, String msg, String time) throws Exception {
URLConnection conn = null;
InputStream is = null;
try {
String soap = getSoapSmssend(userid, pass, mobiles, msg, time);
if (soap == null) {
return null;
}
try {
URL url = new URL("http://service2.winic.org:8003/Service.asmx");
conn = url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Length",
Integer.toString(soap.length()));
conn.setRequestProperty("Content-Type",
"text/xml; charset=utf-8");
conn.setRequestProperty("HOST", "service2.winic.org");
conn.setRequestProperty("SOAPAction",
"\"http://tempuri.org/SendMessages\"");
OutputStream os = conn.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "utf-8");
osw.write(soap);
osw.flush();
} catch (Exception ex) {
System.out.print("SmsSoap.openUrl error:" + ex.getMessage());
}
try {
is = conn.getInputStream();
} catch (Exception ex1) {
System.out.print("SmsSoap.getUrl error:" + ex1.getMessage());
}
return is;
} catch (Exception e) {
System.out.print("SmsSoap.InputStream error:" + e.getMessage());
return null;
}
}
public static void main(String[] args) throws IOException {
String randomCode = RandomStringUtils.randomNumeric(4);
// System.out.println(sendSmsByHTTP("xxx", randomCode));
// System.out.println(sendSmsByHTTP("xxx", "尊敬的用户您好,本次获取的验证码为:"
// + randomCode + ",服务电话:4006184000"));
System.out.println(sendSmsByWebService("xxx", "尊敬的用户您好,本次获取的验证码为:"
+ randomCode + ",服务电话:4006184000"));
}
}
15.✔★注册用户,并发送激活邮件
@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")
public class CustomerAction extends BaseAction<Customer> {
@Autowired
@Qualifier("jmsQueueTemplate")
private JmsTemplate jmsTemplate;
@Action(value = "customer_sendSms")
public String sendSms() throws IOException {
// 手机号保存在Customer对象
// 生成短信验证码
String randomCode = RandomStringUtils.randomNumeric(4);
// 将短信验证码 保存到session
ServletActionContext.getRequest().getSession()
.setAttribute(model.getTelephone(), randomCode);
System.out.println("生成手机验证码为:" + randomCode);
// 编辑短信内容
final String msg = "尊敬的用户您好,本次获取的验证码为:" + randomCode
+ ",服务电话:4006184000";
// 调用MQ服务,发送一条消息
jmsTemplate.send("bos_sms", new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
MapMessage mapMessage = session.createMapMessage();
mapMessage.setString("telephone", model.getTelephone());
mapMessage.setString("msg", msg);
return mapMessage;
}
});
return NONE;
}
// 属性驱动
private String checkcode;
public void setCheckcode(String checkcode) {
this.checkcode = checkcode;
}
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Action(value = "customer_regist", results = {
@Result(name = "success", type = "redirect", location = "signup-success.html"),
@Result(name = "input", type = "redirect", location = "signup.html") })
public String regist() {
// 先校验短信验证码,如果不通过,调回注册页面
// 从session获取 之前生成验证码
String checkcodeSession = (String) ServletActionContext.getRequest()
.getSession().getAttribute(model.getTelephone());
if (checkcodeSession == null || !checkcodeSession.equals(checkcode)) {
System.out.println("短信验证码错误...");
// 短信验证码错误
return INPUT;
}
// 调用webService 连接CRM 保存客户信息
WebClient
.create(Constants.CRM_MANAGEMENT_URL + "/services"
+ "/customerService/customer")
.type(MediaType.APPLICATION_JSON).post(model);
System.out.println("客户注册成功...");
// 发送一封激活邮件
// 生成激活码
String activecode = RandomStringUtils.randomNumeric(32);
// 将激活码保存到redis,设置24小时失效
redisTemplate.opsForValue().set(model.getTelephone(), activecode, 24,
TimeUnit.HOURS);
// 调用MailUtils发送激活邮件
String content = "尊敬的客户您好,请于24小时内,进行邮箱账户的绑定,点击下面地址完成绑定:<br/><a href='"
+ MailUtils.activeUrl + "?telephone=" + model.getTelephone()
+ "&activecode=" + activecode + "'>速运快递邮箱绑定地址</a>";
MailUtils.sendMail("速运快递激活邮件", content, model.getEmail());
return SUCCESS;
}
// 属性驱动
private String activecode;
public void setActivecode(String activecode) {
this.activecode = activecode;
}
16.✔★点击邮件中的激活链接,绑定邮箱
一.用户注册时,输入邮件
二.Javamail技术,向用户邮箱发送一封激活邮件,含有激活码
1.CustomerAction提供发送含激活码的邮件的方法,激活码保存在Redis中
三.用户在24小时内,可以点击激活邮件链接,绑定邮箱
1.CustomerAction提供activeMail方法,接收客户手机号和激活码
2.先判断激活码是否有效,如果激活码无效,提示用户
3.如果激活码有效,判断是否在重复绑定(T_CUSTOMER表type字段为1,绑定)
4.如果用户没有绑定过邮箱,完成绑定
@Action("customer_activeMail")
public String activeMail() throws IOException {
ServletActionContext.getResponse().setContentType(
"text/html;charset=utf-8");
// 判断激活码是否有效
String activecodeRedis = redisTemplate.opsForValue().get(
model.getTelephone());
if (activecodeRedis == null || !activecodeRedis.equals(activecodeRedis)) {
// 激活码无效
ServletActionContext.getResponse().getWriter()
.println("激活码无效,请登录系统,重新绑定邮箱!");
} else {
// 激活码有效
// 防止重复绑定
// 调用CRM webService 查询客户信息,判断是否已经绑定
Customer customer = WebClient
.create(Constants.CRM_MANAGEMENT_URL + "/services"
+ "/customerService/customer/telephone/"
+ model.getTelephone())
.accept(MediaType.APPLICATION_JSON).get(Customer.class);
if (customer.getType() == null || customer.getType() != 1) {
// 没有绑定,进行绑定
WebClient.create(
Constants.CRM_MANAGEMENT_URL + "/services"
+ "/customerService/customer/updatetype/"
+ model.getTelephone()).get();
ServletActionContext.getResponse().getWriter()
.println("邮箱绑定成功!");
} else {
// 已经绑定过
ServletActionContext.getResponse().getWriter()
.println("邮箱已经绑定过,无需重复绑定!");
}
// 删除redis的激活码
redisTemplate.delete(model.getTelephone());
}
return NONE;
}
用户登录功能
@Action(value = "customer_login", results = {
@Result(name = "login", location = "login.html", type = "redirect"),
@Result(name = "success", location = "index.html#/myhome", type = "redirect") })
public String login() {
Customer customer = WebClient
.create(Constants.CRM_MANAGEMENT_URL
+ "/services/customerService/customer/login?telephone="
+ model.getTelephone() + "&password="
+ model.getPassword())
.accept(MediaType.APPLICATION_JSON).get(Customer.class);
if (customer == null) {
// 登录失败
return LOGIN;
} else {
// 登录成功
ServletActionContext.getRequest().getSession()
.setAttribute("customer", customer);
return SUCCESS;
}
}
}
17.后端系统 宣传活动的添加
一.页面form表单,添加Action
<script type="text/javascript">
$(function(){
// 先将body隐藏,再显示,不会出现页面刷新效果
$("body").css({visibility:"visible"});
// 收派标准信息表格
$('#grid').datagrid( {
iconCls : 'icon-forward',
fit : true,
border : false,
rownumbers : true,
striped : true,
pageList: [30,50,100],
pagination : true,
toolbar : toolbar,
url : "../../standard_pageQuery.action",
idField : 'id',
columns : columns
});
二.点击保存按钮,提交表单
// 对收派标准 save按钮,添加click事件
$("#save").click(function(){
// 判断是否form中所有表单对象 都是通过校验
if($("#standardForm").form('validate')){
// 通过校验
$("#standardForm").submit();
}else{
$.messager.alert("警告","表单中还存在需要一些非法内容","warning");
}
});
});
//工具栏
var toolbar = [ {
id : 'button-add',
text : '增加',
iconCls : 'icon-add',
handler : function(){
$("#standardWindow").window('open');
}
}, {
id : 'button-edit',
text : '修改',
iconCls : 'icon-edit',
handler : function(){
// 获取当前datagrid选中数据
var rows = $("#grid").datagrid('getSelections');
if(rows.length != 1){
// 没选 或 多选
$.messager.alert("提示信息","修改数据时,只能选中一行","warning");
}else{
// 只选中一行
var row = rows[0];
// 进行表单回显操作
$("#standardForm").form('load',row);
// 显示窗口
$("#standardWindow").window('open');
}
}
} ];
三.编写PromotionAction,提供save方法
@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")
public class PromotionAction extends BaseAction<Promotion> {
private File titleImgFile;
private String titleImgFileFileName;
public void setTitleImgFileFileName(String titleImgFileFileName) {
this.titleImgFileFileName = titleImgFileFileName;
}
public void setTitleImgFile(File titleImgFile) {
this.titleImgFile = titleImgFile;
}
@Autowired
private PromotionService promotionService;
@Action(value = "promotion_save", results = { @Result(name = "success", type = "redirect", location = "./pages/take_delivery/promotion.html") })
public String save() throws IOException {
// 宣传图 上传、在数据表保存 宣传图路径
String savePath = ServletActionContext.getServletContext().getRealPath(
"/upload/");
String saveUrl = ServletActionContext.getRequest().getContextPath()
+ "/upload/";
// 生成随机图片名
UUID uuid = UUID.randomUUID();
String ext = titleImgFileFileName.substring(titleImgFileFileName
.lastIndexOf("."));
String randomFileName = uuid + ext;
// 保存图片 (绝对路径)
File destFile = new File(savePath + "/" + randomFileName);
System.out.println(destFile.getAbsolutePath());
FileUtils.copyFile(titleImgFile, destFile);
// 将保存路径 相对工程web访问路径,保存model中
model.setTitleImg(ServletActionContext.getRequest().getContextPath()
+ "/upload/" + randomFileName);
// 调用业务层,完成活动任务数据保存
promotionService.save(model);
return SUCCESS;
}
18.后端系统 宣传活动的分页展示
一.在datagrid中添加url
<div class="easyui-window" title="对收派标准进行添加或者修改" id="standardWindow" collapsible="false" minimizable="false" maximizable="false" modal="true" closed="true" style="width:600px;top:50px;left:200px">
<div region="north" style="height:31px;overflow:hidden;" split="false" border="false">
<div class="datagrid-toolbar">
<a id="save" icon="icon-save" href="#" class="easyui-linkbutton" plain="true">保存</a>
</div>
</div>
<div region="center" style="overflow:auto;padding:5px;" border="false">
<form id="standardForm"
action="../../standard_save.action" method="post">
<table class="table-edit" width="80%" align="center">
<tr class="title">
<td colspan="2">收派标准信息
<!--提供隐藏域 装载id -->
<input type="hidden" name="id" />
</td>
</tr>
<tr>
<td>收派标准名称</td>
<td>
<input type="text" name="name"
class="easyui-validatebox" data-options="required:true" />
</td>
</tr>
<tr>
<td>最小重量</td>
<td>
<input type="text" name="minWeight"
class="easyui-numberbox" required="true" />
</td>
</tr>
<tr>
<td>最大重量</td>
<td>
<input type="text" name="maxWeight" class="easyui-numberbox" required="true" />
</td>
</tr>
<tr>
<td>最小长度</td>
<td>
<input type="text" name="minLength" class="easyui-numberbox" required="true" />
</td>
</tr>
<tr>
<td>最大长度</td>
<td>
<input type="text" name="maxLength" class="easyui-numberbox" required="true" />
</td>
</tr>
</table>
</form>
</div>
</div>
二.在PromotionAction中添加pageQuery方法
@Action(value = "promotion_pageQuery", results = { @Result(name = "success", type = "json") })
public String pageQuery() {
// 构造分页查询参数
Pageable pageable = new PageRequest(page - 1, rows);
// 调用业务层 完成查询
Page<Promotion> pageData = promotionService.findPageData(pageable);
// 压入值栈
pushPageDataToValueStack(pageData);
return SUCCESS;
}
19.前端系统 宣传活动分页
一.使用AngularJs动态加载数据,显示动态数据表格
<div class="col-sm-6 col-md-3" ng-repeat="item in pageItems">
<div class="thumbnail">
<img ng-src="{{item.titleImg}}" alt="活动一">
<div class="caption">
<p><a href="#/promotion_detail/{{item.id}}">{{item.title}}</a></p>
<p class="text-right status">
<span ng-show="item.status == '1'">进行中</span>
<span ng-show="item.status == '2'">已结束</span>
</p>
<p class="text-right grey">{{item.startDate}}—{{item.endDate}}</p>
<p class="text-right grey">{{item.activeScope}}</p>
</div>
</div>
</div>
</div>
</tbody>
</table>
<script src="js/self/page.js"></script>
二.基于Angular实现分页工具条功能
<!-- 分页按钮 -->
<div>
<ul class="pagination pull-right">
<li>
<a href ng-click="prev()">上一页</a>
</li>
<li ng-repeat="page in pageList" ng-class="{active: isActivePage(page)}">
<a ng-click="selectPage(page)">{{ page }}</a>
</li>
<li>
<a href ng-click="next()">下一页</a>
</li>
</ul>
</div>
</div>
</section>
</div>
三.修改promotion.html页面分页列表page.js中请求路径
bosfore_app.controller("ctrlRead", ['$scope', '$http', function($scope, $http) {
$scope.currentPage = 1;
$scope.pageSize = 4;
$scope.totalCount = 0;
$scope.totalPages = 0;
$scope.prev = function() {
if($scope.currentPage > 1) {
$scope.selectPage($scope.currentPage - 1);
}
}
$scope.next = function() {
if($scope.currentPage < $scope.totalPages) {
$scope.selectPage($scope.currentPage + 1);
}
}
$scope.selectPage = function(page) {
// 如果页码超出范围
if($scope.totalPages != 0) {
if(page < 1 || page > $scope.totalPages) return;
}
$http({
method: 'GET',
url: 'promotion_pageQuery.action',
params: {
"page": page, // 当前页码
"rows": $scope.pageSize // 每页记录数
}
}).success(function(data, status, headers, config) {
// 显示表格数据
$scope.pageItems = data.pageData;
// 计算总页数
$scope.totalCount = data.totalCount;
$scope.totalPages = Math.ceil($scope.totalCount / $scope.pageSize);
// 当前显示页,设为当前页
$scope.currentPage = page;
// 固定显示10页 (前5后4)
var begin;
var end;
begin = page - 5;
if(begin < 0) {
begin = 1;
}
end = begin + 9;
if(end > $scope.totalPages) {
end = $scope.totalPages;
}
begin = end - 9;
if(begin < 1) {
begin = 1;
}
$scope.pageList = new Array();
for(var i = begin; i <= end; i++) {
$scope.pageList.push(i);
}
}).error(function(data, status, headers, config) {
// 当响应以错误状态返回时调用
alert("出错,请联系管理员 ");
});
}
$scope.isActivePage = function(page) {
return page == $scope.currentPage;
}
// 发起请求 显示第一页数据
$scope.selectPage($scope.currentPage);
}]);
四.在bos_fore项目新建PromotionAction提供pageQuery方法
@Action(value = "promotion_pageQuery", results = { @Result(name = "success", type = "json") })
public String pageQuery() {
System.out.println("11110000000000000000000000000000000000000000000");
// 基于WebService 获取 bos_management的 活动列表 数据信息
PageBean<Promotion> pageBean = WebClient
.create(Constants.BOS_MANAGEMENT_URL+"/services/promotionService/pageQuery?page="
+ page + "&rows=" + rows)
.accept(MediaType.APPLICATION_JSON).get(PageBean.class);
ActionContext.getContext().getValueStack().push(pageBean);
return SUCCESS;
}
五.在bos_management项目提供webService服务,根据page和rows返回分页数据
public interface PromotionService {
// 保存宣传任务
void save(Promotion promotion);
// 分页查询
Page<Promotion> findPageData(Pageable pageable);
// 根据page和rows 返回分页数据
@Path("/pageQuery")
@GET
@Produces({ "application/xml", "application/json" })
PageBean<Promotion> findPageData(@QueryParam("page") int page,
@QueryParam("rows") int rows);
// 根据id 查询
@Path("/promotion/{id}")
@GET
@Produces({ "application/xml", "application/json" })
Promotion findById(@PathParam("id") Integer id);
// 设置活动过期
void updateStatus(Date date);
}
六.在bos_domain中创建PageBean对象
// 自定义 分页数据封装对象
@XmlRootElement(name = "pageBean")
@XmlSeeAlso({ Promotion.class })
public class PageBean<T> {
private long totalCount; // 总记录数
private List<T> pageData; // 当前页数据
public long getTotalCount() {
return totalCount;
}
public void setTotalCount(long totalCount) {
this.totalCount = totalCount;
}
public List<T> getPageData() {
return pageData;
}
public void setPageData(List<T> pageData) {
this.pageData = pageData;
}
}
七.在Promotion加入@XmlRootElement(name=”Promotion”)
@Entity
@Table(name = "T_PROMOTION")
@XmlRootElement(name = "promotion")
public class Promotion implements Serializable {
八.在PromotionService提供WebService服务接口方法
九.在bos_management配置WebService配置文件(web.xml applicationContext-webService.xml)
<!-- spring配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- spring核心监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>CXFService</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFService</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<!--shiro的Filter -->
<filter>
<!--去spring配置文件中寻找同名的本 -->
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- struts2 过滤器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
applicationContext-webService.xml
<jaxrs:server id="promotionService" address="/promotionService">
<jaxrs:serviceBeans>
<bean class="cn.itcast.bos.service.take_delivery.impl.PromotionServiceImpl" />
</jaxrs:serviceBeans>
<jaxrs:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
</jaxrs:inInterceptors>
<jaxrs:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
</jaxrs:outInterceptors>
</jaxrs:server>
20.前端系统 宣传活动详情页面静态化
一.安装插件(将freemarker_eclipseplugin复制在eclipse的dropins文件夹,再重启)
二.编辑freemarker的模版文件(放在WEB-INF)
<html>
<title>
${title}
</title>
<body>
${msg}
</body>
</html>
三.修改promotion.html的href(点击不同链接,拼接上不同id)”#/promotion_detail/{{item.id}}”
四.修改index.html(添加angularjS路由)
五.在PromotionAction提供showDetail方法
//先判断id对应html是否存在,如果存在,直接返回
String htmlRealPath=ServletActionContext.getServletContext().getRealPath(“/freemarker”);
File htmlFile =new File(htmlRealPath+”/”+model.getID()+”.html”);
@Action(value = "promotion_showDetail")
public String showDetail() throws Exception {
// 先判断 id 对应html 是否存在,如果存在 直接返回
String htmlRealPath = ServletActionContext.getServletContext()
.getRealPath("/freemarker");
File htmlFile = new File(htmlRealPath + "/" + model.getId() + ".html");
// 如果html文件不存在 ,查询数据库,结合freemarker模板生成 页面
if (!htmlFile.exists()) {
Configuration configuration = new Configuration(
Configuration.VERSION_2_3_22);
configuration.setDirectoryForTemplateLoading(new File(
ServletActionContext.getServletContext().getRealPath(
"/WEB-INF/freemarker_templates")));
// 获取模板对象
Template template = configuration
.getTemplate("promotion_detail.ftl");
// 动态数据
Promotion promotion = WebClient
.create(Constants.BOS_MANAGEMENT_URL
+ "/services/promotionService/promotion/"
+ model.getId()).accept(MediaType.APPLICATION_JSON)
.get(Promotion.class);
Map<String, Object> parameterMap = new HashMap<String, Object>();
parameterMap.put("promotion", promotion);
// 合并输出
template.process(parameterMap, new OutputStreamWriter(
new FileOutputStream(htmlFile), "utf-8"));
}
// 存在 ,直接将文件返回
ServletActionContext.getResponse().setContentType(
"text/html;charset=utf-8");
FileUtils.copyFile(htmlFile, ServletActionContext.getResponse()
.getOutputStream());
return NONE;
}
六.在bos_management修改PromotionService加入服务接口
21.后端系统 宣传活动自动过期
思路:修改Promotion数据表的status字段,在bos_management中使用,在bos_management集成quartz
一.在common_parent引入定时框架
二.在bos_management编写继承Job和继承JobFactory的类
public class PromotionJob implements Job {
@Autowired
private PromotionService promotionService;
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("活动过期处理程序执行....");
// 每分钟执行一次,当前时间 大于 promotion数据表 endDate, 活动已经过期,设置status='2'
promotionService.updateStatus(new Date());
}
@Service("jobFactory")
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle)
throws Exception {
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
三.配置applicationContext-quartz.xml
<bean id="promotionJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="cn.itcast.bos.quartz.PromotionJob" />
</bean>
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="promotionJob" />
<property name="startDelay" value="0" />
<property name="repeatInterval" value="6000000" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory" ref="jobFactory" />
<property name="triggers">
<list>
<ref bean="simpleTrigger"/>
</list>
</property>
</bean>
22.前端系统 用户登录
一.修改login.html中表单路径
<section class="mainlogin" ng-app="validationApp" ng-controller="mainController">
<div class="container">
<div class="col-md-4 col-md-offset-7 loginbox">
<h4>用户登录</h4>
<form class="form-horizontal" id="customerForm"
action="customer_login.action" method="post">
<div class="form-group">
<label class="col-sm-3 control-label">登录方式</label>
<div class="col-sm-7">
<label for="r1" class="radio-inline"><input type="radio" value="0" name="article" onclick="show()" checked/>密码登录</label>
<label for="r2" class="radio-inline"><input type="radio" value="1" name="article" onclick="show()" />手机号登录</label>
</div>
</div>
<div id="format1">
<div class="form-group" ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }">
<label for="inputaccount" class="col-sm-3 control-label">账号</label>
<div class="col-sm-8">
<input type="text" name="telephone" class="form-control"
ng-model="user.name" required placeholder="请输入账号">
<p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">用户名不可为空.</p>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error' : userForm.username.$invalid && !userForm.username.$pristine }">
<label for="inputpassword" class="col-sm-3 control-label">密码</label>
<div class="col-sm-8">
<input type="password"
class="form-control"
name="password"
placeholder="请输入您的密码"
ng-model="user.password"
ng-minlength="3"
ng-maxlength="8"
required
>
<p ng-show="userForm.password.$error.minlength" class="help-block">用户名太短了!</p>
<p ng-show="userForm.password.$error.maxlength" class="help-block">用户名太长了!</p>
</div>
</div>
<div class="form-group" style="margin-bottom: 0;">
<label for="inputvalidate" class="col-sm-3 control-label">验证码</label>
<div class="col-sm-5">
<input type="password" class="form-control" id="inputaccount" placeholder="请输入验证码">
</div>
<div class="col-sm-3">
<img src="images/icon/yanz.png">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-4">
<div class="checkbox">
<input type="checkbox"><span class="size12"> 记住用户名</span>
</div>
</div>
</div>
</div>
<div id="format2" style="display:none;">
<div class="form-group">
<label for="inputPassword3" class="col-sm-3 control-label">手机号</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="inputaccount" placeholder="请输入手机号/邮箱/用户名">
</div>
</div>
<div class="form-group">
<label for="inputvalidate" class="col-sm-3 control-label">验证码</label>
<div class="col-sm-4">
<input type="password" class="form-control" id="inputaccount" placeholder="验证码">
</div>
<div class="col-sm-3">
<button class="btn btn-default">获取验证码</button>
</div>
</div>
</div>
<div class="col-md-offset-3 col-md-8">
<a href="javascript:$('#customerForm').submit();" class="btn btn-danger" >登录</a>
</div>
<p class="text-right clearfix">还不是我们的会员?<b><a href="signup.html">立即注册</a></b></p>
</form>
</div>
</div>
</section>
二.编写bos_fore系统CustomerAction提供login方法
@Action(value = "customer_login", results = {
@Result(name = "login", location = "login.html", type = "redirect"),
@Result(name = "success", location = "index.html#/myhome", type = "redirect") })
public String login() {
Customer customer = WebClient
.create(Constants.CRM_MANAGEMENT_URL
+ "/services/customerService/customer/login?telephone="
+ model.getTelephone() + "&password="
+ model.getPassword())
.accept(MediaType.APPLICATION_JSON).get(Customer.class);
if (customer == null) {
// 登录失败
return LOGIN;
} else {
// 登录成功
ServletActionContext.getRequest().getSession()
.setAttribute("customer", customer);
return SUCCESS;
}
}
23.前端系统 用户下单
一.前端页面添加city pciker和百度地图API实现相应功能
<!--
描述:用户下单页面
-->
<html>
<head>
<meta content="application/xhtml+xml;charset=UTF-8" http-equiv="Content-Type">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>速运快递</title>
<link rel="stylesheet" type="text/css" href="css/styleindex.css">
<link rel="stylesheet" type="text/css" href="css/public.css">
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap.css">
<link rel="stylesheet" type="text/css" href="css/nav.css">
<script src="js/jquery.min.js" type="text/javascript"></script>
<script src="js/bootstrap.min.js" type="text/javascript"></script>
<script src="js/self/effect.js" type="text/javascript"></script>
<script type="text/javascript" src="js/angular.min.js"></script>
<script type="text/javascript" src="js/angular-route.min.js"></script>
<!--[if IE]>
<script src="js/html5.js" type="text/javascript"></script>
<script src="js/respond.min.js" type="text/javascript"></script>
<![endif]-->
</head>
<link href="css/city-picker.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" type="text/css" href="css/styleorder.css">
<script type="text/javascript">
// 百度地图API功能
function G(id) {
return document.getElementById(id);
}
var ac = new BMap.Autocomplete( //建立一个自动完成的对象
{"input" : "sendAddress"
});
ac.addEventListener("onhighlight", function(e) { //鼠标放在下拉列表上的事件
var str = "";
var _value = e.fromitem.value;
var value = "";
if (e.fromitem.index > -1) {
value = _value.province + _value.city + _value.district + _value.street + _value.business;
}
str = "FromItem<br />index = " + e.fromitem.index + "<br />value = " + value;
value = "";
if (e.toitem.index > -1) {
_value = e.toitem.value;
value = _value.province + _value.city + _value.district + _value.street + _value.business;
}
str += "<br />ToItem<br />index = " + e.toitem.index + "<br />value = " + value;
G("searchResultPanel").innerHTML = str;
});
var myValue;
ac.addEventListener("onconfirm", function(e) { //鼠标点击下拉列表后的事件
var _value = e.item.value;
myValue = _value.province + _value.city + _value.district + _value.street + _value.business;
G("searchResultPanel").innerHTML ="onconfirm<br />index = " + e.item.index + "<br />myValue = " + myValue;
// 选中详细地址后,调用百度地图获取 云地理编码
var address = encodeURIComponent(myValue);
$.getJSON(
"http://api.map.baidu.com/cloudgc/v1?ak=zbLsuDDL4CS2U0M4KezOZZbGUY9iWtVf&address="+address+"&callback=?",
function(data){
if(data.status == 0 && data.result.length>0 ){
$('#sendAreaInfo').citypicker('reset');
$('#sendAreaInfo').citypicker('destroy');
$('#sendAreaInfo').citypicker({
province: data.result[0].address_components.province ,
city: data.result[0].address_components.city ,
district: data.result[0].address_components.district ,
});
}
});
});
</script>
<div class="order" id="ng-app" ng-app="app">
<!-- orderall -->
<section>
<div class="tab-title ">
<ul class="nav nav-tabs container" role="tablist">
<li role="presentation" class="active">
<a href="#home" aria-controls="home" role="tab" data-toggle="tab">单件下单</a>
</li>
<li role="presentation">
<a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">批量下单</a>
</li>
</ul>
</ul>
</div>
<div class="tab-content container">
<div class="jiangli">
<div class="col-md-4 xiaojf">
<h5>消费积分奖励</h5>
<p class="grey">消费1元积1分,累计积分兑好礼</p>
</div>
<div class="col-md-4 tenjf">
<h5>消费积分奖励</h5>
<p class="grey">消费1元积1分,累计积分兑好礼</p>
</div>
<div class="col-md-4 qianjf">
<h5>消费积分奖励</h5>
<p class="grey">消费1元积1分,累计积分兑好礼</p>
</div>
</div>
<div role="tabpanel" class="tab-pane fade in active" id="home">
<ul class="nav nav-tabs">
<li role="presentation" class="active">
<a href="#one" aria-controls="home" role="tab" data-toggle="tab">国内</a>
</li>
<li role="presentation">
<a href="#two" aria-controls="profile" role="tab" data-toggle="tab">港澳台</a>
</li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane fade in active" id="one">
<form id="orderForm" class="form-horizontal" action="order_add.action" method="post">
<!--寄件人信息 -->
<div class="model">
<div class="areatitle">
<h4><span class="zhezhao">寄件人信息</span></h4>
</div>
<div class="col-md-5">
<div class="orderinfo">
<div class="form-group " id="sender-group">
<label class="col-sm-3 control-label"><b>*</b>姓名:</label>
<div class="col-sm-8 input-group" style="padding:0 15px;">
<input name="sendName" type="text" class="form-control" placeholder="请输入发件人姓名" required="required">
<div class="input-group-addon">
<button type="button" data-toggle="modal" data-target="#myModal" id="dao"><img src="images/icon/suyun/contact.png"></button>
</div>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">关闭</span></button>
<h4 class="modal-title" id="myModalLabel"><strong>从地址薄导入</strong></h4>
</div>
<div class="modal-body">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#person" role="tab" data-toggle="tab">个人地址</a>
</li>
<li role="presentation">
<a href="#all" role="tab" data-toggle="tab">常用地址</a>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="form-group col-md-5">
<input type="password" class="form-control" id="inputPassword" placeholder="输入姓名/手机号/地址查询">
</div>
<button type="submit" class="btn btn-danger new">搜索</button>
<table class="table table-striped">
<thead>
<tr>
<th>姓名</th>
<th>联系方式</th>
<th>公司名</th>
<th>详细地址</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div role="tabpanel" class="tab-pane active clearfix" id="person">个人地址</div>
<div role="tabpanel" class="tab-pane" id="all">常用地址</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">确定</button>
</div>
</div>
</div>
</div>
<!-- Modal end -->
</div>
</div>
<div class="form-group" id="mobile-group">
<label class="col-sm-3 control-label"><b>*</b>联系方式:</label>
<div class="col-sm-8">
<input name="sendMobile" type="text" class="form-control" placeholder="请输入联系电话" required="required">
</div>
</div>
<div class="form-group" id="sendcompany-group">
<label class="col-sm-3 control-label">寄件公司:</label>
<div class="col-sm-8">
<input name="sendCompany" type="text" class="form-control" placeholder="请输入寄件公司">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">省市区:</label>
<div class="col-sm-8 province">
<div class="docs-methods">
<div id="distpicker">
<div class="form-group">
<div class="innercity">
<input id="sendAreaInfo" name="sendAreaInfo" class="form-control" readonly type="text" data-toggle="city-picker">
</div>
<button class="btn btn-warning" id="reset" type="button" style="float: right;padding: 8px;">重置</button>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="sendAddress" class="col-sm-3 control-label"><b>*</b>详细地址:</label>
<div class="col-sm-8">
<input id="sendAddress" name="sendAddress" type="text" class="form-control" placeholder="街道详细(精确到门牌号) " required="required">
<div id="searchResultPanel" style="border:1px solid #C0C0C0;width:150px;height:auto; display:none;"></div>
<p class="error">
请填写正确的信息
</p>
</div>
</div>
</div>
</div>
<div class="col-md-7"></div>
</div>
<!--收件人信息 -->
<div class="model clearfix">
<div class="areatitle">
<h4><span class="zhezhao">收件人信息</span></h4>
</div>
<div class="col-md-5">
<div class="orderinfo">
<div class="form-group" id="sender-group">
<label class="col-sm-3 control-label"><b>*</b>姓名:</label>
<div class="col-sm-8 input-group" style="padding:0 15px;">
<input name="recName" type="text" class="form-control" style="z-index: 0;" placeholder="请输入收件人姓名" required="required">
<div class="input-group-addon">
<button type="button" data-toggle="modal" data-target="#myModal" id="dao"><img src="images/icon/suyun/contact.png"></button>
</div>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">关闭</span></button>
<h4 class="modal-title" id="myModalLabel"><strong>从地址薄导入</strong></h4>
</div>
<div class="modal-body">
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#person" role="tab" data-toggle="tab">个人地址</a>
</li>
<li role="presentation">
<a href="#all" role="tab" data-toggle="tab">常用地址</a>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="form-group col-md-5">
<input type="text" class="form-control" id="inputPassword" placeholder="输入姓名/手机号/地址查询">
</div>
<button type="submit" class="btn btn-danger new">搜索</button>
<table class="table table-striped">
<thead>
<tr>
<th>姓名</th>
<th>联系方式</th>
<th>公司名</th>
<th>详细地址</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div role="tabpanel" class="tab-pane active clearfix" id="person">个人地址</div>
<div role="tabpanel" class="tab-pane" id="all">常用地址</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">确定</button>
</div>
</div>
</div>
</div>
<!-- Modal end -->
</div>
</div>
<div class="form-group" id="mobile-group">
<label class="col-sm-3 control-label"><b>*</b>联系方式:</label>
<div class="col-sm-8">
<input name="recMobile" type="text" class="form-control" placeholder="请输入收件人电话" required="required">
</div>
</div>
<div class="form-group" id="sendcompany-group">
<label class="col-sm-3 control-label">收件公司:</label>
<div class="col-sm-8">
<input name="recCompany" type="text" class="form-control" placeholder="请输入收件公司">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">省市区:</label>
<div class="col-sm-8 province">
<div class="docs-methods">
<div id="distpicker">
<div class="form-group">
<div class="innercity">
<input name="recAreaInfo" id="recAreaInfo" class="form-control" readonly type="text" data-toggle="city-picker">
</div>
<button class="btn btn-warning" id="reset2" type="button" style="float: right;padding: 8px;">重置</button>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-sm-3 control-label"><b>*</b>详细地址:</label>
<div class="col-sm-8">
<input name="recAddress" type="text" class="form-control" placeholder="街道详细(精确到门牌号) " required="required">
</div>
</div>
</div>
</div>
<div class="col-md-7"></div>
</div>
<div class="partline"></div>
<!--快件信息 -->
<div class="model clearfix">
<div class="areatitle">
<h4><span class="zhezhao">快件信息</span></h4>
</div>
<div class="col-md-5">
<div class="orderinfo">
<div class="form-group" id="sender-group">
<label class="col-sm-3 control-label"><b>*</b>拖寄物:</label>
<div class="col-sm-8">
<select class="form-control" name="goodsType">
<option>文件</option>
<option>衣服</option>
<option>食品</option>
<option>电子产品</option>
</select>
</div>
</div>
<div class="form-group" id="mobile-group">
<label class="col-sm-3 control-label">重量:</label>
<div class="col-sm-8">
<input name="weight" type="text" class="form-control" placeholder="请输入重量" required="required">
</div>
</div>
<div class="form-group" id="sendcompany-group">
<label class="col-sm-3 control-label">备注:</label>
<div class="col-sm-8">
<input name="remark" type="text" class="form-control" placeholder="备注不超过20个字">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">快递产品:</label>
<div class="col-sm-8">
<select class="form-control" name="sendProNum">
<option>速运当日</option>
<option>速运次日</option>
<option>速运隔日</option>
</select>
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-sm-3 control-label">付款方式:</label>
<div class="col-sm-8">
<select class="form-control" name="payTypeNum">
<option>寄付日结</option>
<option>寄付月结</option>
<option>到付</option>
</select>
</div>
</div>
</div>
</div>
<div class="col-md-7"></div>
</div>
<div class="partline"></div>
<!--预约-->
<div class="model clearfix">
<div class="col-md-5">
<div class="orderinfo">
<div class="form-group" id="mobile-group">
<label class="col-sm-3 control-label">给小哥捎话:</label>
<div class="col-sm-8">
<input name="sendMobileMsg" type="text" class="form-control" placeholder="有什么要提醒快递员的吗?" required="required">
</div>
</div>
</div>
</form>
</div>
<div class="col-md-7"></div>
</div>
</form>
</div>
<div role="tabpanel" class="tab-pane fade" id="two">港澳台待定</div>
</div>
</div>
<div role="tabpanel" class="tab-pane fade" id="profile">
<div class="model">
<div class="areatitle">
<h4><span class="zhezhao">寄件人信息</span></h4>
</div>
<div class="col-md-5">
<form class="form-horizontal" name="OrderForm" ng-submit="submitForm()">
<div class="orderinfo">
<div class="form-group" id="sender-group">
<label class="col-sm-3 control-label"><b>*</b>姓名:</label>
<div class="col-sm-8">
<input name="sendName" type="text" class="form-control" placeholder="请输入发件人姓名" ng-model="orderdata.sendName" required="required">
</div>
</div>
<div class="form-group" id="mobile-group">
<label class="col-sm-3 control-label"><b>*</b>联系方式:</label>
<div class="col-sm-8">
<input name="sendMobile" type="text" class="form-control" placeholder="请输入联系电话" ng-model="orderdata.sendMobile" required="required">
</div>
</div>
<div class="form-group" id="sendcompany-group">
<label class="col-sm-3 control-label">寄件公司:</label>
<div class="col-sm-8">
<input name="sendCompany" type="text" class="form-control" placeholder="请输入寄件公司" ng-model="orderdata.sendCompany">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">省市区:</label>
<div class="col-sm-8">
<input name="sendArea" type="text" class="form-control" placeholder="请填写正确的省市区" ng-model="orderdata.sendArea">
</div>
</div>
<div class="form-group">
<label for="inputPassword" class="col-sm-3 control-label"><b>*</b>详细地址:</label>
<div class="col-sm-8">
<input name="sendAddress" type="text" class="form-control" placeholder="街道详细(精确到门牌号) " ng-model="orderdata.sendAddress" required="required">
</div>
</div>
</div>
</form>
</div>
<div class="col-md-7"></div>
</div>
<div class="partline clearfix"></div>
<div class="daoru">
<p>
<a href="#" class="btn btn-default" data-toggle="modal" data-target="#ExcelModal">导入Excel</a>
<a href="#" class="btn btn-default">从地址薄导入</a>
<input type="button" onclick="Click()" value="下载Excel" class="btn btn-danger">
</p>
</div>
<!--导入excel-->
<div class="modal fade" id="ExcelModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel"><strong>导入Excel模板</strong></h4>
</div>
<div class="modal-body" ng-controller="AppController" nv-file-drop="" uploader="uploader" filters="queueLimit, customFilter">
<center><img src="images/icon/xlsLogo.png" class="img-responsive"></center>
<div class="row excel">
<div class="col-md-6">
<input type="file" nv-file-select="" uploader="uploader" />
</div>
<div class="col-md-6">
<div>
<span style="float:left">上传进度:</span>
<div class="progress" style="">
<div class="progress-bar" role="progressbar" ng-style="{ 'width': uploader.progress + '%' }"></div>
</div>
</div>
</div>
<button type="button" class="btn btn-success btn-s" ng-click="uploader.uploadAll()" ng-disabled="!uploader.getNotUploadedItems().length">
<span class="glyphicon glyphicon-upload"></span> 上传
</button>
<button type="button" class="btn btn-danger btn-s" ng-click="uploader.clearQueue()" ng-disabled="!uploader.queue.length">
<span class="glyphicon glyphicon-trash"></span> 删除
</button>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary">确定</button>
</div>
</div>
</div>
</div>
<div class="searchset">
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input type="text" class="form-control" id="exampleInputAmount" placeholder="请输入姓名/电话/地址">
<div class="input-group-addon btn btn-danger">搜索</div>
</div>
</div>
<input type="checkbox" /><span class="typetext">只显示错误信息</span>
</form>
<div class="setbtn">
<a href="#" class="btn btn-danger">批量设置</a>
<a href="#" class="btn btn-default">删除</a>
</div>
</div>
<!--piliang-->
<table class="table table-striped clearfix">
<tr>
<td><input type="checkbox" /> 收件人姓名</td>
<td>收件人联系电话 </td>
<td>收件人公司 </td>
<td>省 </td>
<td>市</td>
<td>区</td>
<td>详细地址</td>
</tr>
</table>
</div>
<div class="col-md-11 submit">
<div class="xieyi"><input type="checkbox" checked="checked" />我已阅读并同意《快件运单契约条款》 </div>
<div class="tijiao">
<div class="tjtext">
<p class="red">1、如果您在周六、日等法定节假日期间寄件,将会做相应加时。(以上“预计时效”已做相应加时)</p>
<p class="red">2、如果您收方地址属于偏远地区,在“预计时效”基础上需增加0.5天.</p>
</div>
</div>
</div>
<div class="col-md-1 ordertj">
<a href="javascript:$('#orderForm').submit();" class="btn btn-danger" >提交</a>
</div>
</div>
</section>
</div>
<script src="js/self/city-picker.data.js"></script>
<script src="js/self/city-picker.js"></script>
<script src="js/angular-file-upload.min.js"></script>
<script src="js/console-sham.min.js"></script>
<script src="js/self/controllers.js"></script>
<script src="js/self/main.js"></script>
<script src="js/self/effect.js"></script>
<script>
function Click() {
$('a[rel*=downloadr]').downloadr()
}
</script>
二.自动分单逻辑:分单的方式(根据用户填写的区域和地址信息,查询快递员的过程)
(一)根据区域和地址一起查询快递员。
1.先根据区域的信息,在数据库中查询区域对象,从区域对象中获取管理的分区对象列表
2.循环分区对象列表,获取分区关键字,和用户输入的地址比较,是否包含关键字,找到当前用户输入的地址属于哪个具体的分区。
3.根据查到的分区对象,获得其定区对象
4.定区和快递员是多对多关系,但是一个排班时间中,只有一个快递员
5.选中当前班次的快递员,让他去。
(二)根据定区关联的客户查询快递员
1.根据用户输入的地址信息,通过webservice在CRM系统中,查询定区的ID
2.根据定区ID,查询定区对象
3.定区和快递员是多对多关系,但是一个排班时间中,只有一个快递员
4.选中当前班次的快递员,让他去。
(三)第二种根据关联客户的信息查询快递员更加准确,所以应该先判断是否关联了定区,没有关联定区的时候,才判断分区信息。如果上述两种情况,都没有匹配快递员,进入人工分单。
三.前端表单提交,基于WebService将数据传递后台系统
1.在bos_fore系统,添加OrderAction封装订单数据
@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")
public class OrderAction extends BaseAction<Order> {
private String sendAreaInfo; // 发件人省市区 信息
private String recAreaInfo; // 收件人 省市区信息
public void setSendAreaInfo(String sendAreaInfo) {
this.sendAreaInfo = sendAreaInfo;
}
public void setRecAreaInfo(String recAreaInfo) {
this.recAreaInfo = recAreaInfo;
}
@Action(value = "order_add", results = { @Result(name = "success", type = "redirect", location = "index.html") })
public String add() {
System.out.println(sendAreaInfo+"地址在+++++++++++++++++++++++++++++++");
// 手动封装 Area关联
Area sendArea = new Area();
String[] sendAreaData = sendAreaInfo.split("/");
sendArea.setProvince(sendAreaData[0]);
sendArea.setCity(sendAreaData[1]);
sendArea.setDistrict(sendAreaData[2]);
Area recArea = new Area();
System.out.println(recAreaInfo);
String[] recAreaData = recAreaInfo.split("/");
recArea.setProvince(recAreaData[0]);
recArea.setCity(recAreaData[1]);
recArea.setDistrict(recAreaData[2]);
model.setSendArea(sendArea);
model.setRecArea(recArea);
// 关联当前登录客户
Customer customer = (Customer) ServletActionContext.getRequest()
.getSession().getAttribute("customer");
model.setCustomer_id(customer.getId());
// 调用WebService 将数据传递 bos_management系统
WebClient
.create(Constants.BOS_MANAGEMENT_URL
+ "/services/orderService/order")
.type(MediaType.APPLICATION_JSON).post(model);
return SUCCESS;
}
2.修改bos_domain 添加@XmlRootElement
@Entity
@Table(name = "T_ORDER")
@XmlRootElement(name = "order")
public class Order {
3.在bos_management中添加OrderService发布WebService
public interface OrderService {
@Path("/order")
@POST
@Consumes({ "application/xml", "application/json" })
public void saveOrder(Order order);
public Order findByOrderNum(String orderNum);
}
4.配置applicationContext-webService.xml
<jaxrs:server id="orderService" address="/orderService">
<jaxrs:serviceBeans>
<bean class="cn.itcast.bos.service.take_delivery.impl.OrderServiceImpl" />
</jaxrs:serviceBeans>
<jaxrs:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
</jaxrs:inInterceptors>
<jaxrs:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
</jaxrs:outInterceptors>
</jaxrs:server>
5.完善bos_fore的OrderAction代码,调用WebService
四.自动分单—基于CRM地址完全匹配自动分单
1.在crm_management中CustomerService添加根据地址获取定区编码方法
public interface CustomerService {
// 查询所有未关联客户列表
@Path("/noassociationcustomers")
@GET
@Produces({ "application/xml", "application/json" })
public List<Customer> findNoAssociationCustomers();
// 已经关联到指定定区的客户列表
@Path("/associationfixedareacustomers/{fixedareaid}")
@GET
@Produces({ "application/xml", "application/json" })
public List<Customer> findHasAssociationFixedAreaCustomers(
@PathParam("fixedareaid") String fixedAreaId);
// 将客户关联到定区上 , 将所有客户id 拼成字符串 1,2,3
@Path("/associationcustomerstofixedarea")
@PUT
public void associationCustomersToFixedArea(
@QueryParam("customerIdStr") String customerIdStr,
@QueryParam("fixedAreaId") String fixedAreaId);
@Path("/customer")
@POST
@Consumes({ "application/xml", "application/json" })
public void regist(Customer customer);
@Path("/customer/telephone/{telephone}")
@GET
@Consumes({ "application/xml", "application/json" })
public Customer findByTelephone(@PathParam("telephone") String telephone);
@Path("/customer/updatetype/{telephone}")
@GET
public void updateType(@PathParam("telephone") String telephone);
@Path("customer/login")
@GET
@Consumes({ "application/xml", "application/json" })
public Customer login(@QueryParam("telephone") String telephone,
@QueryParam("password") String password);
@Path("/customer/findFixedAreaIdByAddress")
@GET
@Consumes({ "application/xml", "application/json" })
public String findFixedAreaIdByAddress(@QueryParam("address") String address);
}
2.修改bos_management的OrderService
第三阶段
24.✔★后端系统 运单快速录入
一.在表单上添加列属性editor
二.调用datagrid的方法,对指定数据行开启编辑功能
三.在表格插入一行新的数据,进行编辑
<script type="text/javascript">
var editIndex ;
function doAdd(){
if(editIndex != undefined){
$("#grid").datagrid('endEdit',editIndex);
}
if(editIndex==undefined){
//alert("快速添加电子单...");
$("#grid").datagrid('insertRow',{
index : 0,
row : {}
});
$("#grid").datagrid('beginEdit',0);
editIndex = 0;
}
}
function doSave(){
$("#grid").datagrid('endEdit',editIndex );
}
function doCancel(){
if(editIndex!=undefined){
$("#grid").datagrid('cancelEdit',editIndex);
if($('#grid').datagrid('getRows')[editIndex].id == undefined){
$("#grid").datagrid('deleteRow',editIndex);
}
editIndex = undefined;
}
}
//工具栏
var toolbar = [ {
id : 'button-add',
text : '新增一行',
iconCls : 'icon-edit',
handler : doAdd
}, {
id : 'button-cancel',
text : '取消编辑',
iconCls : 'icon-cancel',
handler : doCancel
}, {
id : 'button-save',
text : '保存',
iconCls : 'icon-save',
handler : doSave
}];
// 定义列
var columns = [ [ {
field : 'wayBillNum',
title : '运单号',
width : 120,
align : 'center',
editor :{
type : 'validatebox',
options : {
required: true
}
}
}, {
field : 'arriveCity',
title : '到达地',
width : 120,
align : 'center',
editor :{
type : 'validatebox',
options : {
required: true
}
}
},{
field : 'goodsType',
title : '货物类型',
width : 120,
align : 'center',
editor :{
type : 'validatebox',
options : {
required: true
}
}
}, {
field : 'num',
title : '件数',
width : 120,
align : 'center',
editor :{
type : 'numberbox',
options : {
required: true
}
}
}, {
field : 'weight',
title : '重量',
width : 120,
align : 'center',
editor :{
type : 'validatebox',
options : {
required: true
}
}
}, {
field : 'floadreqr',
title : '配载要求',
width : 220,
align : 'center',
editor :{
type : 'validatebox',
options : {
required: true
}
}
}] ];
$(function(){
// 先将body隐藏,再显示,不会出现页面刷新效果
$("body").css({visibility:"visible"});
// 运单数据表格
$('#grid').datagrid( {
iconCls : 'icon-forward',
fit : true,
border : true,
rownumbers : true,
striped : true,
pageList: [30,50,100],
pagination : true,
toolbar : toolbar,
url : "../../waybill_pageQuery.action",
idField : 'id',
columns : columns,
onDblClickRow : doDblClickRow,
onAfterEdit : function(rowIndex, rowData, changes){
// 将新添加运单数据 保存到 数据表中
$.post("../../waybill_save.action",rowData, function(data){
// data数据格式 {success:true, msg:'xxxx'}
if(data.success){
// 保存成功
$.messager.show({
title:'提示窗口',
msg: data.msg,
});
// 刷新列表
$("#grid").datagrid('reload');
}
});
console.info(rowData);
editIndex = undefined;
}
});
});
function doDblClickRow(rowIndex, rowData){
alert("双击表格数据...");
console.info(rowIndex);
$('#grid').datagrid('beginEdit',rowIndex);
editIndex = rowIndex;
}
</script>
四.服务器代码上创建WayBillAction提供save方法
// 运单管理
@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")
public class WayBillAction extends BaseAction<WayBill> {
private static final Logger LOGGER = Logger.getLogger(WayBillAction.class);
@Autowired
private WayBillService wayBillService;
@Action(value = "waybill_save", results = { @Result(name = "success", type = "json") })
public String save() {
Map<String, Object> result = new HashMap<String, Object>();
try {
// 去除 没有id的order对象
if (model.getOrder() != null
&& (model.getOrder().getId() == null || model.getOrder()
.getId() == 0)) {
model.setOrder(null);
}
wayBillService.save(model);
// 保存成功
result.put("success", true);
result.put("msg", "保存运单成功!");
LOGGER.info("保存运单成功,运单号:" + model.getWayBillNum());
} catch (Exception e) {
e.printStackTrace();
// 保存失败
result.put("success", false);
result.put("msg", "保存运单失败!");
LOGGER.error("保存运单失败,运单号:" + model.getWayBillNum(), e);
}
ActionContext.getContext().getValueStack().push(result);
return SUCCESS;
}
25.✔★后端系统 运单录入
一.订单数据回显表单
1.对订单号输入框,添加onblur离焦事件
<script type="text/javascript">
$(function() {
$("body").css({
visibility: "visible"
});
// 对save按钮条件 点击事件
$('#save').click(function() {
// 对form 进行校验
$.post("../../waybill_save.action",$("#waybillForm").serialize(),function(data){
// data数据格式 {success:true, msg:'xxxx'}
if(data.success){
// 保存成功
$.messager.show({
title:'提示窗口',
msg: data.msg,
});
// 重置表单
$("#waybillForm").get(0).reset();
$("input[name='order.id']").val('');
}
});
});
// 对订单号输入项 添加 blur事件
$("#orderNum").blur(function(){
// 发起Ajax请求,查询订单数据
$.post("../../order_findByOrderNum.action",{orderNum: $(this).val()},
function(data){
// 封装结果数据 { success:true , orderData: {} }
if(data.success){
// 装载数据
$("#waybillForm").form('load',data.orderData) ;
// 处理无法自动load 元素
$("input[name='order.id']").val(data.orderData.id);
$("input[name='order.orderNum']").val(data.orderData.orderNum);
$("input[name='order.courier.company']").val(data.orderData.courier.company);
$("input[name='order.courier.name']").val(data.orderData.courier.name);
}else{
// 订单号 不存在,重置表单
$("#waybillForm").get(0).reset();
}
});
});
// 对运单快速录入数据进行回显
$("#wayBillNum").blur(function(){
// 发起Ajax请求
$.post("../../waybill_findByWayBillNum.action",{wayBillNum: $(this).val()},
function(data){
// 封装结果数据 { success:true , wayBillData: {} }
if(data.success){
// 装载数据
$("#waybillForm").form('load',data.wayBillData) ;
}
});
});
});
</script>
2.在OrderAction添加findByOrderNum方法
@Autowired
private OrderService orderService;
@Action(value="order_findByOrderNum",results={@Result(name="success",type="json")})
public String findByOrderNum(){
//调用业务层,查询order信息
Order order=orderService.findByOrderNum(model.getOrderNum());
Map<String,Object> result=new HashMap<>();
if(order==null){
//订单号不存在
result.put("success", false);
}else{
//订单号存在
result.put("success", true);
result.put("orderData", order);
}
ActionContext.getContext().getValueStack().push(result);
return SUCCESS;
}
二.采用运单快速录入的数据回显表单
思路:对运单号输入框,添加onblur事件,根据运单号查询,查询到信息回显表单
1.对运单数据项添加blur事件
2.服务器代码wayBillAction提供findByWayBillNum方法
@Action(value = "waybill_findByWayBillNum", results = { @Result(name = "success", type = "json") })
public String findByWayBillNum() {
// 调用业务层 查询
WayBill wayBill = wayBillService
.findByWayBillNum(model.getWayBillNum());
Map<String, Object> result = new HashMap<String, Object>();
if (wayBill == null) {
// 运单不存在
result.put("success", false);
} else {
// 运单存在
result.put("success", true);
result.put("wayBillData", wayBill);
}
ActionContext.getContext().getValueStack().push(result);
return SUCCESS;
}
三.运单录入数据保存
1.点击页面保存按钮,提交表单访问WayBillAction的save方法
private static final Logger LOGGER = Logger.getLogger(WayBillAction.class);
@Autowired
private WayBillService wayBillService;
@Action(value = "waybill_save", results = { @Result(name = "success", type = "json") })
public String save() {
Map<String, Object> result = new HashMap<String, Object>();
try {
// 去除 没有id的order对象
if (model.getOrder() != null
&& (model.getOrder().getId() == null || model.getOrder()
.getId() == 0)) {
model.setOrder(null);
}
wayBillService.save(model);
// 保存成功
result.put("success", true);
result.put("msg", "保存运单成功!");
LOGGER.info("保存运单成功,运单号:" + model.getWayBillNum());
} catch (Exception e) {
e.printStackTrace();
// 保存失败
result.put("success", false);
result.put("msg", "保存运单失败!");
LOGGER.error("保存运单失败,运单号:" + model.getWayBillNum(), e);
}
ActionContext.getContext().getValueStack().push(result);
return SUCCESS;
}
26.✔★运单管理
一.运单列表显示—–(条件查询)全文检索
1.在bos_management引入elasticsearch和spring data elasticsearch 的支持
<!-- elasticsearch -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
2.在实体类WayBill对象,添加elasticsearch索引和映射信息操作bos_domain项目
@Entity
@Table(name = "T_WAY_BILL")
@Document(indexName = "bos", type = "waybill")
public class WayBill implements Serializable {
@Id
@GeneratedValue
@Column(name = "C_ID")
@org.springframework.data.annotation.Id
@Field(index = FieldIndex.not_analyzed, store = true, type = FieldType.Integer)
private Integer id;
@Column(name = "C_WAY_BILL_NUM", unique = true)
@Field(index = FieldIndex.not_analyzed, store = true, type = FieldType.String)
private String wayBillNum; // 运单编号
@OneToOne
@JoinColumn(name = "C_ORDER_ID")
private Order order; // 订单信息
@Column(name = "C_SEND_NAME")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String sendName; // 寄件人姓名
@Column(name = "C_SEND_MOBILE")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String sendMobile;// 寄件人电话
@Column(name = "C_SEND_COMPANY")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String sendCompany;// 寄件人公司
@OneToOne
@JoinColumn(name = "C_SEND_AREA_ID")
private Area sendArea; // 寄件人省市区信息
@Column(name = "C_SEND_ADDRESS")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String sendAddress;// 寄件人详细地址信息
@Column(name = "C_REC_NAME")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String recName;// 收件人姓名
@Column(name = "C_REC_MOBILE")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String recMobile;// 收件人电话
@Column(name = "C_REC_COMPANY")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String recCompany;// 收件人公司
@OneToOne
@JoinColumn(name = "C_REC_AREA_ID")
private Area recArea; // 收件人省市区信息
@Column(name = "C_REC_ADDRESS")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String recAddress;// 收件人详细地址信息
@Column(name = "C_SEND_PRO_NUM")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String sendProNum; // 快递产品类型编号:速运当日、速运次日、速运隔日
@Column(name = "C_GOODS_TYPE")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String goodsType;// 托寄物类型:文件、衣服 、食品、电子商品
@Column(name = "C_PAY_TYPE_NUM")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String payTypeNum;// 支付类型编号:寄付日结、寄付月结、到付
@Column(name = "C_WEIGHT")
@Field(index = FieldIndex.no, store = true, type = FieldType.String)
private Double weight;// 托寄物重量
@Column(name = "C_REMARK")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String remark; // 备注
@Column(name = "C_NUM")
@Field(index = FieldIndex.no, store = true, type = FieldType.String)
private Integer num; // 原件数
@Column(name = "C_ARRIVE_CITY")
@Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String)
private String arriveCity; // 到达地
@Column(name = "C_FEEITEMNUM")
@Field(index = FieldIndex.no, store = true, type = FieldType.String)
private Integer feeitemnum; // 实际件数
@Column(name = "C_ACTLWEIT")
@Field(index = FieldIndex.no, store = true, type = FieldType.String)
private Double actlweit; // 实际重量
@Column(name = "C_VOL")
@Field(index = FieldIndex.no, store = true, type = FieldType.String)
private String vol; // 体积 输入格式为1*1*1*1,表示长*宽*高*数量
@Column(name = "C_FLOADREQR")
@Field(index = FieldIndex.no, store = true, type = FieldType.String)
private String floadreqr; // 配载要求 (比如录入1=无,2=禁航,4=禁航空铁路)
@Column(name = "C_WAY_BILL_TYPE")
private String wayBillType; // 运单类型(类型包括:正常单据、异单、调单)
/*
* 运单状态: 1 待发货、 2 派送中、3 已签收、4 异常
*/
@Column(name = "C_SIGN_STATUS")
@Field(index = FieldIndex.not_analyzed, store = true, type = FieldType.String)
private Integer signStatus; // 签收状态
/*
* 1、新增修改单据状态为“否” 2、作废时需将状态置为“是” 3、取消作废时需要将状态置为“否”
*/
@Column(name = "C_DELTAG")
private String delTag; // 作废标志
public String getArriveCity() {
return arriveCity;
}
public void setArriveCity(String arriveCity) {
this.arriveCity = arriveCity;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getWayBillNum() {
return wayBillNum;
}
public void setWayBillNum(String wayBillNum) {
this.wayBillNum = wayBillNum;
}
@JsonIgnore
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
public String getSendName() {
return sendName;
}
public void setSendName(String sendName) {
this.sendName = sendName;
}
public String getSendMobile() {
return sendMobile;
}
public void setSendMobile(String sendMobile) {
this.sendMobile = sendMobile;
}
public String getSendCompany() {
return sendCompany;
}
public void setSendCompany(String sendCompany) {
this.sendCompany = sendCompany;
}
@JsonIgnore
public Area getSendArea() {
return sendArea;
}
public void setSendArea(Area sendArea) {
this.sendArea = sendArea;
}
public String getSendAddress() {
return sendAddress;
}
public void setSendAddress(String sendAddress) {
this.sendAddress = sendAddress;
}
public String getRecName() {
return recName;
}
public void setRecName(String recName) {
this.recName = recName;
}
public String getRecMobile() {
return recMobile;
}
public void setRecMobile(String recMobile) {
this.recMobile = recMobile;
}
public String getRecCompany() {
return recCompany;
}
public void setRecCompany(String recCompany) {
this.recCompany = recCompany;
}
@JsonIgnore
public Area getRecArea() {
return recArea;
}
public void setRecArea(Area recArea) {
this.recArea = recArea;
}
public String getRecAddress() {
return recAddress;
}
public void setRecAddress(String recAddress) {
this.recAddress = recAddress;
}
public String getSendProNum() {
return sendProNum;
}
public void setSendProNum(String sendProNum) {
this.sendProNum = sendProNum;
}
public String getGoodsType() {
return goodsType;
}
public void setGoodsType(String goodsType) {
this.goodsType = goodsType;
}
public String getPayTypeNum() {
return payTypeNum;
}
public void setPayTypeNum(String payTypeNum) {
this.payTypeNum = payTypeNum;
}
public Double getWeight() {
return weight;
}
public void setWeight(Double weight) {
this.weight = weight;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Integer getNum() {
return num;
}
public void setNum(Integer num) {
this.num = num;
}
public Integer getFeeitemnum() {
return feeitemnum;
}
public void setFeeitemnum(Integer feeitemnum) {
this.feeitemnum = feeitemnum;
}
public Double getActlweit() {
return actlweit;
}
public void setActlweit(Double actlweit) {
this.actlweit = actlweit;
}
public String getVol() {
return vol;
}
public void setVol(String vol) {
this.vol = vol;
}
public String getFloadreqr() {
return floadreqr;
}
public void setFloadreqr(String floadreqr) {
this.floadreqr = floadreqr;
}
public String getWayBillType() {
return wayBillType;
}
public void setWayBillType(String wayBillType) {
this.wayBillType = wayBillType;
}
public Integer getSignStatus() {
return signStatus;
}
public void setSignStatus(Integer signStatus) {
this.signStatus = signStatus;
}
public String getDelTag() {
return delTag;
}
public void setDelTag(String delTag) {
this.delTag = delTag;
}
}
3.配置elasticsearch applicationContext-elasticsearch.xml
<!-- 搜索DAO 扫描 -->
<elasticsearch:repositories base-package="cn.itcast.bos.index" />
<!-- 配置Client -->
<elasticsearch:transport-client id="client" cluster-nodes="127.0.0.1:9300"/>
<!-- 配置搜索模板 -->
<bean id="elasticsearchTemplate"
class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client" />
</bean>
4.操作索引库,创建dao继承ElasticsearchRepository
public interface WayBillIndexRepository extends
ElasticsearchRepository<WayBill, Integer> {
public List<WayBill> findBySendAddress(String sendAddress);
}
5.修改Service代码添加保存索引的方法
@Service
@Transactional
public class WayBillServiceImpl implements WayBillService {
@Autowired
private WayBillRepository wayBillRepository;
@Autowired
private WayBillIndexRepository wayBillIndexRepository;
@Override
public void save(WayBill wayBill) {
// 判断运单号是否存在
WayBill persistWayBill = wayBillRepository.findByWayBillNum(wayBill
.getWayBillNum());
if (persistWayBill == null || persistWayBill.getId() == null) {
// 运单不存在
wayBill.setSignStatus(1); // 待发货
wayBillRepository.save(wayBill);
// 保存索引
wayBillIndexRepository.save(wayBill);
} else {
// 运单存在
try {
// 判断运单状态是否 为待发货
if (persistWayBill.getSignStatus() == 1) {
Integer id = persistWayBill.getId();
BeanUtils.copyProperties(persistWayBill, wayBill);
persistWayBill.setId(id);
persistWayBill.setSignStatus(1);// 待发货
// 保存索引
wayBillIndexRepository.save(persistWayBill);
} else {
// 运单状态 已经运输中,不能修改
throw new RuntimeException("运单已经发出,无法修改保存!!");
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
}
二.搜索运单,基于索引库查询
1.将查询form的数据,转换json格式,绑定数据表格上
2.修改WayBillAction的pageQuery方法
@Action(value = "waybill_pageQuery", results = { @Result(name = "success", type = "json") })
public String pageQuery() {
// 无条件查询
Pageable pageable = new PageRequest(page - 1, rows, new Sort(
new Sort.Order(Sort.Direction.DESC, "id")));
// 调用业务层进行查询
Page<WayBill> pageData = wayBillService.findPageData(model, pageable);
// 压入值栈返回
pushPageDataToValueStack(pageData);
return SUCCESS;
}
3.编写业务层findPageData方法
@Override
public Page<WayBill> findPageData(WayBill wayBill, Pageable pageable) {
// 判断WayBill 中条件是否存在
if (StringUtils.isBlank(wayBill.getWayBillNum())
&& StringUtils.isBlank(wayBill.getSendAddress())
&& StringUtils.isBlank(wayBill.getRecAddress())
&& StringUtils.isBlank(wayBill.getSendProNum())
&& (wayBill.getSignStatus() == null || wayBill.getSignStatus() == 0)) {
// 无条件查询 、查询数据库
return wayBillRepository.findAll(pageable);
} else {
// 查询条件
// must 条件必须成立 and
// must not 条件必须不成立 not
// should 条件可以成立 or
BoolQueryBuilder query = new BoolQueryBuilder(); // 布尔查询 ,多条件组合查询
// 向组合查询对象添加条件
if (StringUtils.isNoneBlank(wayBill.getWayBillNum())) {
// 运单号查询
QueryBuilder tempQuery = new TermQueryBuilder("wayBillNum",
wayBill.getWayBillNum());
query.must(tempQuery);
}
if (StringUtils.isNoneBlank(wayBill.getSendAddress())) {
// 发货地 模糊查询
// 情况一: 输入"北" 是查询词条一部分, 使用模糊匹配词条查询
QueryBuilder wildcardQuery = new WildcardQueryBuilder(
"sendAddress", "*" + wayBill.getSendAddress() + "*");
// 情况二: 输入"北京市海淀区" 是多个词条组合,进行分词后 每个词条匹配查询
QueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(
wayBill.getSendAddress()).field("sendAddress")
.defaultOperator(Operator.AND);
// 两种情况取or关系
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
boolQueryBuilder.should(wildcardQuery);
boolQueryBuilder.should(queryStringQueryBuilder);
query.must(boolQueryBuilder);
}
if (StringUtils.isNoneBlank(wayBill.getRecAddress())) {
// 收货地 模糊查询
QueryBuilder wildcardQuery = new WildcardQueryBuilder(
"recAddress", "*" + wayBill.getRecAddress() + "*");
query.must(wildcardQuery);
}
if (StringUtils.isNoneBlank(wayBill.getSendProNum())) {
// 速运类型 等值查询
QueryBuilder termQuery = new TermQueryBuilder("sendProNum",
wayBill.getSendProNum());
query.must(termQuery);
}
if (StringUtils.isNoneBlank(wayBill.getSendProNum())) {
// 速运类型 等值查询
QueryBuilder termQuery = new TermQueryBuilder("sendProNum",
wayBill.getSendProNum());
query.must(termQuery);
}
if (wayBill.getSignStatus() != null && wayBill.getSignStatus() != 0) {
// 签收状态查询
QueryBuilder termQuery = new TermQueryBuilder("signStatus",
wayBill.getSignStatus());
query.must(termQuery);
}
SearchQuery searchQuery = new NativeSearchQuery(query);
searchQuery.setPageable(pageable); // 分页效果
// 有条件查询 、查询索引库
return wayBillIndexRepository.search(searchQuery);
}
}
27.权限控制 用户登录
一.配置shiro的Filter实现URL级别权限控制
1.web.xml(shiroFilter) applicationContext-shiro.xml(核心shiroFilter的bean、安全管理器)
web.xml
<!--shiro的Filter -->
<filter>
<!--去spring配置文件中寻找同名的本 -->
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--shiro核心Filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--安全管理器 -->
<property name="securityManager" ref="securityManager"></property>
<!--未认证,跳转到哪个页面 -->
<property name="loginUrl" value="/login.html"/>
<!--登录页面-->
<property name="successUrl" value="/index.html"/>
<!--认证后,没有权限跳转页面 -->
<property name="unauthorizedUrl" value="/unauthorized.html"></property>
<!--shiro URL控制过滤器规则 -->
<property name="filterChainDefinitions">
<value>
/login.html*=anon
/user_login.action*=anon
/validatecode.jsp*=anon
/css/**=anon
/js/**=anon
/images/**=anon
/services/**=anon
/upload/**=anon
/attached/**=anon
/pages/base/courier.html*=perms[courier:list]
/pages/base/area.html*=roles[base]
/**=authc
</value>
</property>
</bean>
<!--安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="bosRealm"></property>
<property name="cacheManager" ref="shiroCacheManager"/>
</bean>
<!-- 配置Realm -->
<bean id="bosRealm" class="cn.itcast.bos.realm.BosRealm">
<!--缓存区的名字 就是ehcache.xml 自定义cache的name -->
<property name="authorizationCacheName" value="bos"/>
</bean>
<!--后处理器 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>
<!--开启shiro注解模式 -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true"></property>
</bean>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"></property>
</bean>
二.用户登录(认证)功能实现
1.login.html的form表单设置action
<section class="mainlogin">
<div class="container">
<div class="col-md-4 col-md-offset-7 logincontent">
<h4>员工登录</h4>
<form class="form-horizontal" id="loginform" name="loginform" method="post" action="user_login.action">
<div class="form-group" id="idInputLine">
<label for="inputPassword3" class="col-sm-3 control-label">账号</label>
<div class="col-sm-8">
<input id="loginform:idInput" type="text" name="username" class="form-control" placeholder="请输入手机号/邮箱/用户名">
</div>
</div>
<div class="form-group" id="pwdInputLine">
<label id="loginform:pwdInput" class="col-sm-3 control-label">密码</label>
<div class="col-sm-8">
<input for="pwdInput" type="password" name="password" class="form-control" id="inputaccount" placeholder="请输入您的密码">
</div>
</div>
<div class="form-group">
<label for="inputvalidate" class="col-sm-3 control-label">验证码</label>
<div class="col-sm-4">
<input type="password" class="form-control" id="inputaccount" placeholder="请输入验证码">
</div>
<div class="col-sm-4">
<img id="loginform:vCode" src="validatecode.jsp" onclick="javascript:document.getElementById('loginform:vCode'). src='validatecode.jsp?'+Math.random();" />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-4">
<input type="checkbox"><span class="size12"> 记住用户名</span>
</div>
<div class="col-sm-4">
<a href="#"><span class="size12 forget">忘记密码</span></a>
</div>
</div>
<div class="col-md-offset-3 col-md-8">
<a href="javascript:$('#loginform').submit();" id="loginform:j_id19" name="loginform:j_id19"
class="btn btn-danger" target="_blank">立即登录</a>
</div>
</form>
</div>
</div>
</section>
2.点击登录提交表单
@Action(value="user_login",results={@Result(name="login",type="redirect",location="login.html") ,
@Result(name="success",type="redirect",location="index.html")})
public String login(){
//用户名和密码都保存在model
//基于shiro实现登录
Subject subject=SecurityUtils.getSubject();
//用户名和密码信息
AuthenticationToken token=new UsernamePasswordToken(
model.getUsername(), model.getPassword()
);
try {
subject.login(token);
//登录成功
return SUCCESS;
} catch (AuthenticationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
//登录失败
return LOGIN;
}
}
4.编写BosRealm实现Realm接口,并实现Realm的认证方法
@Service("bosRealm")
public class BosRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
@Autowired
private PermissionService permissionService;
@Override
//授权...
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
System.out.println("shiro 授权管理。。。。");
SimpleAuthorizationInfo authorizationInfo =new SimpleAuthorizationInfo();
//根据当前登录用户查询对应角色和权限
Subject subject=SecurityUtils.getSubject();
User user=(User) subject.getPrincipal();
//调用业务层,查询角色
List<Role> roles=roleService.findByUser(user);
for (Role role : roles) {
authorizationInfo.addRole(role.getKeyword());
}
//调用业务层 ,查询权限
List<Permission> permissions=permissionService.findByUser(user);
for (Permission permission : permissions) {
authorizationInfo.addStringPermission(permission.getKeyword());
}
return authorizationInfo;
}
@Override
//认证。。。
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
System.out.println("shiro认证管理。。。。");
//转换token
UsernamePasswordToken usernamePasswordToken=(UsernamePasswordToken) token;
//根据用户名查询用户信息
User user=userService.findByUsername(usernamePasswordToken.getUsername());
if(user==null){
/**用户名不存在
* 参数一:期望登陆后,保存在Subject中信息
* 参数二:如果返回为null 说明用户不存在,报用户名
* 参数三:realm名称
*/
return null;
}else{
/**用户名存在
* 当返回用户名密码时,securityManager安全管理器,自动比较返回密码和用户输入密码是否一致
* 如果密码一致 登录成功,如果密码不一致 报密码错误异常
*/
System.out.println(user.getPassword()+"+++++++++++++++++++++++");
System.out.println(usernamePasswordToken.getPassword()+"+++++++++++++++++++++++");
return new SimpleAuthenticationInfo(user, user.getPassword(),getName());
}
}
}
28.权限控制 用户授权
一.修改applicationContext-shiro.xml配置shiroFilter权限过滤程序
/pages/base/courier.html*=perms[courier:list]
/pages/base/area.html*=roles[base]
二.实现Realm的授权方法
29.用户注销
一.修改页面退出系统的跳转路径 location.href=’./user_logout.action’
二.在UserAction提供logout方法Subject subject=SecurityUtils.getSubject();
Subject.logout();
@Action(value="user_logout",results={@Result(name="success",type="redirect",location="login.html")})
public String logout(){
//基于shiro完成退出
Subject subject=SecurityUtils.getSubject();
subject.logout();
return SUCCESS;
}
@Autowired
private UserService userService;
@Action(value="user_list",results={@Result(name="success",type="json")})
public String list(){
//调用业务层,返回用户列表
List<User> users=userService.findAll();
ActionContext.getContext().getValueStack().push(users);
return SUCCESS;
}
//属性驱动
private String [] roleIds;
public void setRoleIds(String[] roleIds) {
this.roleIds = roleIds;
}
@Action(value="user_save",results={@Result(name="success",type="redirect",location="pages/system/userlist.html")})
public String save(){
userService.saveUser(model,roleIds);
return SUCCESS;
}
30.授权数据管理:菜单管理
一.菜单列表显示
1.修改menu.html的datagrid的url属性
<script type="text/javascript">
$(function(){
$("#grid").datagrid({
toolbar : [
{
id : 'add',
text : '添加菜单',
iconCls : 'icon-add',
handler : function(){
location.href='menu_add.html';
}
}
],
url : '../../menu_list.action',
columns : [[
{
field : 'id',
title : '编号',
width : 200
},
{
field : 'name',
title : '名称',
width : 200
},
{
field : 'description',
title : '描述',
width : 200
},
{
field : 'priority',
title : '优先级',
width : 200
},
{
field : 'page',
title : '路径',
width : 200
}
]]
});
});
</script>
2.编写MenuAction提供list查询所有菜单方法
二.菜单数据添加
1.检查页面表单元素是否与实体类匹配
2.在MenuAction添加save保存方法
@Action(value="menu_save",results={@Result(name="success",type="redirect",location="pages/system/menu.html")})
public String save(){
//调用业务层,保存菜单数据
menuService.save(model);
return SUCCESS;
}
31.授权数据管理:权限管理
一.权限数据列表显示
1.修改permission.html的datagrid
2.编写PermissionAction添加list查询方法
@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")
public class PermissionAction extends BaseAction<Permission> {
@Autowired
private PermissionService permissionService;
@Action(value="permission_list",results={@Result(name="success",type="json")})
public String list(){
List<Permission> permissions=permissionService.findAll();
ActionContext.getContext().getValueStack().push(permissions);
return SUCCESS;
}
二.权限数据添加
1.更改permiss_add.html的form表单的action
<script type="text/javascript">
$(function(){
// 点击保存
$('#save').click(function(){
if($("#permissionForm").form('validate')){
$("#permissionForm").submit();
}
});
});
</script>
</head>
<body class="easyui-layout">
<div data-options="region:'north'">
<div class="datagrid-toolbar">
<a id="save" icon="icon-save" href="#" class="easyui-linkbutton" plain="true">保存</a>
</div>
</div>
<div data-options="region:'center'">
<form id="permissionForm" method="post" action="../../permission_save.action">
<table class="table-edit" width="80%" align="center">
<tr class="title">
<td colspan="2">权限信息</td>
</tr>
<tr>
<td>名称</td>
<td>
<input type="text" name="name" class="easyui-validatebox" data-options="required:true" />
</td>
</tr>
<tr>
<td>关键字</td>
<td>
<input type="text" name="keyword" class="easyui-validatebox" data-options="required:true" />
</td>
</tr>
<tr>
<td>描述</td>
<td>
<textarea name="description" rows="4" cols="60"></textarea>
</td>
</tr>
</table>
</form>
</div>
</body>
2.服务器代码编写PermissionAction提供save方法
@Action(value="permission_save",results={@Result(name="success",type="redirect",location="pages/system/permission.html")})
public String save(){
permissionService.save(model);
return SUCCESS;
}
32.授权数据管理:角色管理
一.角色列表显示
1.修改role.html的datagrid的url属性
<script type="text/javascript">
$(function(){
// 数据表格属性
$("#grid").datagrid({
toolbar : [
{
id : 'add',
text : '添加角色',
iconCls : 'icon-add',
handler : function(){
location.href='role_add.html';
}
}
],
url : '../../role_list.action',
columns : [[
{
field : 'id',
title : '编号',
width : 200
},
{
field : 'name',
title : '名称',
width : 200
},
{
field : 'keyword',
title : '关键字',
width : 200
},
{
field : 'description',
title : '描述',
width : 200
}
]]
});
});
</script>
2.编写RoleAction添加list
@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")
public class RoleAction extends BaseAction<Role> {
@Autowired
private RoleService roleService;
@Action(value="role_list",results={@Result(name="success",type="json")})
public String list(){
//调用业务层,查询所有角色
List<Role> roles=roleService.findAll();
ActionContext.getContext().getValueStack().push(roles);
return SUCCESS;
}
二.角色数据添加
1.(permission数据)权限checkbox列表显示
2.(menu数据)显示菜单树形选择列表
①修改ztree获取数据的url属性
②修改menu实体类,添加返回pId方法,在json中生成pId属性
@Entity
@Table(name = "T_MENU")
public class Menu implements Serializable {
@Id
@GeneratedValue
@Column(name = "C_ID")
private int id;
@Column(name = "C_NAME")
private String name; // 菜单名称
@Column(name = "C_PAGE")
private String page; // 访问路径
@Column(name = "C_PRIORITY")
private Integer priority; // 优先级
@Column(name = "C_DESCRIPTION")
private String description; // 描述
@ManyToMany(mappedBy = "menus")
private Set<Role> roles = new HashSet<Role>(0);
@OneToMany(mappedBy = "parentMenu")
private Set<Menu> childrenMenus = new HashSet<Menu>();
@ManyToOne
@JoinColumn(name = "C_PID")
private Menu parentMenu;
@Transient
// 在数据表不去生成数据列
public Integer getpId() {
if (parentMenu == null) {
return 0;
} else {
return parentMenu.getId();
}
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
public Integer getPriority() {
return priority;
}
public void setPriority(Integer priority) {
this.priority = priority;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@JSON(serialize = false)
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
@JSON(serialize = false)
public Set<Menu> getChildrenMenus() {
return childrenMenus;
}
public void setChildrenMenus(Set<Menu> childrenMenus) {
this.childrenMenus = childrenMenus;
}
public Menu getParentMenu() {
return parentMenu;
}
public void setParentMenu(Menu parentMenu) {
this.parentMenu = parentMenu;
}
}
3..提交表单,为form指定action(并在页面添加隐藏字段存放勾选菜单的id,”,”分隔)
4.RoleAction提供save方法,完成角色添加、关联权限、关联菜单
//属性驱动
private String [] permissionIds;
private String menuIds;
public void setPermissionIds(String[] permissionIds) {
this.permissionIds = permissionIds;
}
public void setMemuIds(String memuIds) {
this.menuIds = memuIds;
}
@Action(value="role_save",results={@Result(name="success",type="redirect",location="pages/system/role.html")})
public String save(){
//调用业务层,保存角色
roleService.saveRole(model,permissionIds,menuIds);
return SUCCESS;
}
}
33.授权数据管理:用户管理
一.用户数据列表显示
1.在userlist.html修改datagrid的url
$(function(){
// 初始化 datagrid
// 创建grid
$('#grid').datagrid( {
iconCls : 'icon-forward',
fit : true,
border : false,
rownumbers : true,
striped : true,
toolbar : toolbar,
url : "../../user_list.action",
idField : 'id',
frozenColumns : frozenColumns,
columns : columns,
onClickRow : onClickRow,
onDblClickRow : doDblClickRow
});
$("body").css({visibility:"visible"});
});
// 双击
function doDblClickRow(rowIndex, rowData) {
var items = $('#grid').datagrid('selectRow',rowIndex);
doView();
}
// 单击
function onClickRow(rowIndex){
}
function doAdd() {
location.href="../../pages/system/userinfo.html";
}
function doView() {
var item = $('#grid').datagrid('getSelected');
console.info(item);
//window.location.href = "edit.html";
}
function doDelete() {
var ids = [];
var items = $('#grid').datagrid('getSelections');
for(var i=0; i<items.length; i++){
ids.push(items[i].id);
}
console.info(ids.join(","));
$('#grid').datagrid('reload');
$('#grid').datagrid('uncheckAll');
}
</script>
2.在UserAction提供list查询方法
@Autowired
private UserService userService;
@Action(value="user_list",results={@Result(name="success",type="json")})
public String list(){
//调用业务层,返回用户列表
List<User> users=userService.findAll();
ActionContext.getContext().getValueStack().push(users);
return SUCCESS;
}
二.用户添加功能
1.角色checkbox列表显示 在显示角色列表元素添加id=”roleTD”
2.编写form属性,提交表单
3.在UserAction中提供save方法
34.动态菜单功能
一。修改index.html 加载基本菜单url路径
二.在MenuAction中提供showMenu方法
@Action(value="menu_showmenu",results={@Result(name="success",type="json")})
public String showMenu(){
//调用业务层,查询当前用户具有菜单列表
Subject subject =SecurityUtils.getSubject();
User user=(User) subject.getPrincipal();
List<Menu> menus=menuService.findByUser(user);
ActionContext.getContext().getValueStack().push(menus);
return SUCCESS;
}
35.✔★Ehcache 对普通业务数据进行缓存
一.在common_parent导入ehcache maven的坐标
<!-- 缓存 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
</dependency>
二.使用ehcache,导入ehcache.xml
<Cache name="bos"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</Cache>
<Cache name="standard"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</Cache>
三.配置spring整合ehcache 将ehcacheManager交给spring管理
四.配置spring缓存管理器,封装ehcache自带CacheManager
五.在applicationContext-cache.xml引入cach名称空间
六.激活spring缓存注解
<!-- 缓存配置 -->
<bean id="ehCacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>
<!-- shiro封装cacheManager -->
<bean id="shiroCacheManager"
class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="ehCacheManager" />
</bean>
<!-- spring 封装ehcache缓存管理器 -->
<bean id="springCacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehCacheManager" />
</bean>
<!-- 激活spring 缓存注解 -->
<cache:annotation-driven cache-manager="springCacheManager"/>
七.在被spring管理bean对象方法上使用@Cacheable @CacheEvict
standardServiceImpl
public class StandardServiceImpl implements StandardService {
// 注入DAO
@Autowired
private StandardRepository standardRepository;
@Override
@CacheEvict(value="standard",allEntries=true)
public void save(Standard standard) {
standardRepository.save(standard);
}
@Override
@Cacheable("standard")
public List<Standard> findAll() {
return standardRepository.findAll();
}
八.对有参数的方法对其结果数据进行缓存
@Override
@Cacheable(value="standard",key="#pageable.pageNumber+'_'+#pageable.pageSize")
public Page<Standard> findPageData(Pageable pageable) {
return standardRepository.findAll(pageable);
}
第四阶段
36.中转业务模块:运单管理–开启中转配送
一.在waybill_manager.html添加按钮“中转配送”
二.通过js对按钮添加点击事件(将选中的运单的id,提交给服务器)
<script type="text/javascript">
$.fn.serializeJson=function(){
var serializeObj={};
var array=this.serializeArray();
var str=this.serialize();
$(array).each(function(){
if(serializeObj[this.name]){
if($.isArray(serializeObj[this.name])){
serializeObj[this.name].push(this.value);
}else{
serializeObj[this.name]=[serializeObj[this.name],this.value];
}
}else{
serializeObj[this.name]=this.value;
}
});
return serializeObj;
};
function doSearch() {
// 将form内容,转换为json
var queryParams = $("#searchForm").serializeJson();
// 绑定数据表格 重新加载数据
$('#tt').datagrid('load', queryParams);
}
$(function(){
// 开启运输管理 按钮
$("#transitBtn").click(function(){
// 获取数据表格所有选中行
var rows = $("#tt").datagrid('getSelections');
if(rows.length == 0){
// 没有选中
$.messager.alert('警告','必须选中运单信息','warning');
}else{
// 选中运单 ,获取选中运单id
var array = new Array();
for(var i=0; i<rows.length; i++){
array.push(rows[i].id);
}
var wayBillIds = array.join(",");
$.post("../../transit_create.action",{wayBillIds: wayBillIds}, function(data){
// 返回值 {success:true, msg: ...}
if(data.success == true){
$.messager.show({
title:'操作成功',
msg: data.msg
});
}else{
$.messager.show({
title:'操作失败',
msg: data.msg
});
}
});
}
});
三.服务器代码编写TransitInfoAction,提供create方法
@ParentPackage("json-default")
@Namespace("/")
@Controller
@Scope("prototype")
public class TransitInfoAction extends BaseAction<TransitInfo>{
@Autowired
private TransitInfoService transitInfoService;
//属性驱动
private String wayBillIds;
public void setWayBillIds(String wayBillIds) {
this.wayBillIds = wayBillIds;
}
@Action(value="transit_create",results={@Result(name="success",type="json")})
public String create(){
//调用业务层,保存transitInfo信息
Map<String,Object> result=new HashMap<>();
try {
transitInfoService.createTransits(wayBillIds);
//成功
result.put("success", true);
result.put("msg", "开启中转配送成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
//失败
result.put("success", false);
result.put("msg", "开启中转配送失败,异常:"+e.getMessage());
}
ActionContext.getContext().getValueStack().push(result);
return SUCCESS;
}
}
37.中转业务模块:运输配送管理:运输地图显示
一.在显示地图的位置添加div(class=”easyui-window”)
<div class="easyui-window" title="运输路径查看" id="transitPathWindow" modal="true" closed="true" collapsible="false" minimizable="false" maximizable="false" style="top:20px;left:100px;width: 800px; height: 400px">
<div id="allmap"></div>
</div>
<div class="easyui-window" title="实时配送路径" id="deliveryInTimePathWindow" modal="true" closed="true" collapsible="false" minimizable="false" maximizable="false" style="top:20px;left:100px;width: 800px; height:400px">
</div>
二.编写显示地图的方法:(注意:引入百度地图src=”地址&ak”)
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=4IU3oIAMpZhfWZsMu7xzqBBAf6vMHcoa"></script>
// 显示地图
// 百度地图API功能
var map = new BMap.Map("allmap");
map.centerAndZoom('北京', 11);
map.enableScrollWheelZoom(true);
//三种驾车策略:最少时间,最短距离,避开高速
var routePolicy = [BMAP_DRIVING_POLICY_LEAST_TIME, BMAP_DRIVING_POLICY_LEAST_DISTANCE, BMAP_DRIVING_POLICY_AVOID_HIGHWAYS];
var start = row.wayBill.sendAddress;
var end = row.wayBill.recAddress;
// 获取driveringRoute
var driving = new BMap.DrivingRoute(map, {renderOptions:{map: map, autoViewport: true},policy: routePolicy[0]});
// 给id为2路径 添加途经点 北京-上海
if(row.id == "2"){
// 显示路径 带途经点
driving.search(start,end, {waypoints:['南京夫子庙']});
}else{
// 显示路径
driving.search(start,end);
}
// 弹出窗口
$("#transitPathWindow").window('open');
}
}, {
id: 'button-path',
text: '实时配送路径',
iconCls: 'icon-search',
handler: function() {
$("#deliveryInTimePathWindow").window('open');
}
}];
38.中转业务模块:运输配送信息列表查询
一.修改transitinfo.html的datagrid的url地址
二.服务器代码编写TransitInfoAction提供pageQuery方法
@Action(value = "transit_pageQuery", results = { @Result(name = "success", type = "json") })
public String pageQuery() {
// 分页查询
Pageable pageable = new PageRequest(page - 1, rows);
// 调用业务层 查询分页数据
Page<TransitInfo> pageData = transitInfoService.findPageData(pageable);
// 压入值栈返回
pushPageDataToValueStack(pageData);
return SUCCESS;
}
业务层同步索引库
@Service
@Transactional
public class TransitInfoServiceImpl implements TransitInfoService {
@Autowired
private WayBillRepository wayBillRepository;
@Autowired
private TransitInfoRepository transitInfoRepository;
@Autowired
private WayBillIndexRepository wayBillIndexRepository;
@Override
public void createTransits(String wayBillIds) {
if (StringUtils.isNotBlank(wayBillIds)) {
// 处理运单
for (String wayBillId : wayBillIds.split(",")) {
WayBill wayBill = wayBillRepository.findOne(Integer
.parseInt(wayBillId));
// 判断运单状态是否为待发货
if (wayBill.getSignStatus() == 1) {
// 待发货
// 生成TransitInfo信息
TransitInfo transitInfo = new TransitInfo();
transitInfo.setWayBill(wayBill);
transitInfo.setStatus("出入库中转");
transitInfoRepository.save(transitInfo);
// 更改运单状态
wayBill.setSignStatus(2); // 派送中
// 同步索引库
wayBillIndexRepository.save(wayBill);
}
}
}
}
@Override
public Page<TransitInfo> findPageData(Pageable pageable) {
return transitInfoRepository.findAll(pageable);
}
}
39.出入库操作:在弹出窗口中显示 运单配送信息
一.前端代码编写回显方法row.wayBill.属性
// 判断运输状态 ,是否为开始配送
if(row.status == "开始配送"){
// 在表单隐藏域保存 当前操作 中转信息
$("#signId").val(row.id);
// 回显运输配送信息
$("#signTransitInfoView").append("运单号:" + row.wayBill.wayBillNum+"<br/>");
$("#signTransitInfoView").append("货物类型:" + row.wayBill.goodsType+"<br/>");
$("#signTransitInfoView").append("发货地:" + row.wayBill.sendAddress+"<br/>");
$("#signTransitInfoView").append("收货地:" + row.wayBill.recAddress+"<br/>");
$("#signTransitInfoView").append("物流信息:" + row.transferInfo+"<br/>");
// 弹出窗口
$("#signWindow").window('open');
}else{
$.messager.alert('警告','签收录入操作只能针对开始配送状态运单','warning');
return ;
}
40.出入库操作:提交表单,在服务器保存关联出入库信息
一.为出入库表单,指定Action
二.给保存按钮添加点击事件,提交表单到服务器
三.服务器代码编写InOutStorageAction提供save方法
// 出入库操作
@Namespace("/")
@ParentPackage("json-default")
@Controller
@Scope("prototype")
public class InOutStorageInfoAction extends BaseAction<InOutStorageInfo> {
@Autowired
private InOutStorageInfoService inOutStorageInfoService;
private String transitInfoId ;
public void setTransitInfoId(String transitInfoId) {
this.transitInfoId = transitInfoId;
}
@Action(value = "inoutstore_save", results = {
@Result(name = "success", type = "redirect", location = "pages/transit/transitinfo.html") })
public String save() {
inOutStorageInfoService.save(transitInfoId, model);
return SUCCESS;
}
}
41.开始配送功能
思路:选中一条运单信息,点击开始配送按钮,弹出窗口(只针对到达网点运单)
一.为form指定action 给保存按钮添加事件
二.服务器代码编写DeliveryInfoAction的save
@Namespace("/")
@ParentPackage("json-default")
@Controller
@Scope("prototype")
public class DeliveryInfoAction extends BaseAction<DeliveryInfo> {
@Autowired
private DeliveryInfoService deliveryInfoService;
private String transitInfoId;
public void setTransitInfoId(String transitInfoId) {
this.transitInfoId = transitInfoId;
}
@Action(value = "delivery_save", results = { @Result(name = "success", type = "redirect", location = "pages/transit/transitinfo.html") })
public String save() {
deliveryInfoService.save(transitInfoId, model);
return SUCCESS;
}
}
42.✔★签收录入功能
一.对状态为”开始配送“的运单,弹出签收录入窗口
二.为页面form添加action,绑定提交事件
三.服务器代码编写SignlnfoAction提供save方法
@Namespace("/")
@ParentPackage("json-default")
@Controller
@Scope("prototype")
public class SignInfoAction extends BaseAction<SignInfo> {
@Autowired
private SignInfoService signInfoService;
private String transitInfoId;
public void setTransitInfoId(String transitInfoId) {
this.transitInfoId = transitInfoId;
}
@Action(value = "sign_save", results = { @Result(name = "success", type = "redirect", location = "pages/transit/transitinfo.html") })
public String save() {
signInfoService.save(transitInfoId, model);
return SUCCESS;
}
}