由BOS项目几个功能实现谈技术点
1:Oracle安装的常见问题,以及Oracel的常见问题
一.安装配置问题:
二.项目中使用所见问题
2:AngularJS的常见指令及含义
AngularJS指令指示的是“当关联的HTML结构进入编译阶段时应该执行的操作”,它本质上只是一个当编译器编译到相关DOM时需要执行的函数,可以写在元素的名称里,属性里,css类名里,注释里。
指令:ng-app
指令:ng-init
AngularJS表达式
AngularJS框架的核心功能之一 —— 数据绑定,由两个花括号{{}}组成,可以把数据绑定到HTML,类似Javascript代码片段,可以包含文字、运算符和变量,通常在绑定数据中用到,表达式可以绑定数字、字符串、对象、数组,写在双大括号内:{{ expression }}。
指令:ng-model
在AngularJS中,只需要使用ng-model指令就可以把应用程序数据绑定到HTML元素,实现model和view的双向绑定。
指令:ng-bind
指令ng-bind和AngularJS表达式{{}}有异曲同工之妙,但不同之处就在于ng-bind是在angular解析渲染完毕后才将数据显示出来的。
指令:ng-click
AngularJS也有自己的HTML事件指令,比如说通过ng-click定义一个AngularJS单击事件。对按钮、链接等,我们都可以用ng-click指令属性来实现绑定
3:用户注册(fore系统)
用户在注册页面填写基本信息,
点击发送验证码,异步将手机号传给后台的action,调用发送短信的方法,向用户填写的手机号发送验证码,同时将验证码保存到session中,
4:邮件绑定**
邮箱**,后台收到用户提交的邮箱号,调用发送邮件的方法,向用户邮箱发送**邮件,同时将生成的**码保存到redis中,并将**码的有效期设置为24小时。
当用户点击注册时,判断验证码是否与session中保存的验证码一致,若是一致,则将用户存入数据库中,并将用户状态设置为默认的未**状态。
当用户前往邮箱点击**,后台接收到请求,将用户传过来的**码与redis中的**码比较,若是一致,则修改用户状态为已**的状态。
为了减轻服务器的访问压力,这里发送短信可以使用mq消息队列。当请求过多,可以一条一条的处理,以达到减轻服务器压力的目的。
5:消息队列的作用(重点讲解) JMS
ActiveMq是什么? 消息中间件。可以在分布式系统的不同服务之间进行消息的发送和接收;
(activeMQ是一种开源的,实现了JMS1.1规范的,面向消息(MOM)的中间件,为应用程序提供高效的、可扩展的、稳定的和安全的企业级消息通信。)
同类型技术有哪些?
RabbitMQ,Kafka ,ZeroMQ,MetaMQ,RocketMQ
1个标准
Jms标准,JMS(Java Messaging Service)是Java官方定义的技术规范。
JMS 定义了五种不同的消息:
两个角色
Producer(生产者):发消息
Consumer(消费者):收消息
两种消息模式
一对一消息(私聊),Queue消息,同时一个收。
一对多消息(群发),Topic消息,同时可以多个收。
6:Spring整合MQ发送和接收消息
一.先导入相关依赖:
7:运单详情的录入,快速录入,分页排序查询
★★★★后端系统 运单快速录入
一.在表单上添加列属性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
}
}
}] ];
四.服务器代码上创建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;
}
★★★后端系统 运单录入
一.订单数据回显表单
1.对订单号输入框,添加onblur离焦事件
// 对订单号输入项 添加 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();
}
});
});
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事件
// 对运单快速录入数据进行回显
$("#wayBillNum").blur(function(){
// 发起Ajax请求
$.post("../../waybill_findByWayBillNum.action",{wayBillNum: $(this).val()},
function(data){
// 封装结果数据 { success:true , wayBillData: {} }
if(data.success){
// 装载数据
$("#waybillForm").form('load',data.wayBillData) ;
}
});
});
});
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;
}
★★★★★运单管理
一.运单列表显示—–(条件查询)全文检索
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; // 作废标志
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);
}
}
8:elasticsearch,IK分词器
一.在官网上下载好ElasticSearch并解压缩到一个无中文路径的文件夹下
使用注意事项:
1.使用时,运行其bin目录下的elasticSearch.bat
2.一定要配置JAVA_HOME环境变量
3.ElasticSearch服务默认端口9300,web服务管理平台端口9200
4.我们编程步骤一般为:
建立索引对象→建立映射→存储数据【文档】→指定文档类型进行搜索数据【文档】
但是,当我们直接在ElasticSearch建立文档对象时,如果索引不存在,默认会自动创建,映射采用默认方式
//使用步骤如下:
//创建连接搜索服务器对象
Client client=TransportClient.builder().build().addTransportAddress(
new InetSocketTransportAddress(InetAddres.getByName("127.0.0.1"),9300));
//搜索数据
SearchResponse searchResponse=client.prepareSearch("索引名称").setTypes("索引类型").setQuery(QueryBuilders.你想要用的搜索文档数据的方法/查询对象的方法).get();
常见错误
SerializationError:JSON数据序列化出错,通常是因为不支持某个节点值的数据类型
RequestError:提交数据格式不正确
ConflictError:索引ID冲突
TransportError:连接无法建立
9:运单管理功能同步索引库
中转业务模块:运输配送信息列表查询
一.修改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);
}
}
上一篇: 5.HTML标题
推荐阅读