目录
数据库设计
预备知识 mysql数据类型
decimal是小数
shop表:
DROP TABLE IF EXISTS `shop`;
CREATE TABLE `shop` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` datetime(0) NOT NULL DEFAULT '2021-04-10 00:00:00',
`updated_at` datetime(0) NOT NULL DEFAULT '2021-04-10 00:00:00',
`name` varchar(80) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`remark_score` decimal(2, 1) NOT NULL,
`price_per_man` int(11) NOT NULL DEFAULT 0,
`latitude` decimal(10, 6) NOT NULL,
`longitude` decimal(10, 6) NOT NULL,
`category_id` int(11) NOT NULL DEFAULT 0,
`tags` varchar(2000) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`start_time` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`end_time` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`address` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`seller_id` int(11) NOT NULL DEFAULT 0,
`icon_url` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 501 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
user表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` datetime(0) NOT NULL DEFAULT '2021-04-10 00:00:00',
`updated_at` datetime(0) NOT NULL DEFAULT '2021-04-10 00:00:00',
`telphone` varchar(40) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`password` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`nick_name` varchar(40) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`gender` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `telphone_unique_index`(`telphone`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
seller商户表:
DROP TABLE IF EXISTS `seller`;
CREATE TABLE `seller` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(80) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`created_at` datetime(0) NOT NULL DEFAULT '2021-04-10 00:00:00',
`updated_at` datetime(0) NOT NULL DEFAULT '2021-04-10 00:00:00',
`remark_score` decimal(2, 1) NOT NULL,
`disabled_flag` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 27 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
catrgory类目表:
CREATE TABLE `category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` datetime(0) NOT NULL DEFAULT '2021-04-10 00:00:00',
`updated_at` datetime(0) NOT NULL DEFAULT '2021-04-10 00:00:00',
`name` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`icon_url` varchar(200) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`sort` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `name_unique_index`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
用户注册功能:
前端:
<form class="login-form">
<div class="form-group">
<label class="control-label">手机号</label>
<div class="input-icon">
<input class="form-control placeholder-no-fix" type="text" autocomplete="off" placeholder="输入手机号" name="telphone" id="telphone"/>
</div>
</div>
<div class="form-group">
<label class="control-label">密码</label>
<div class="input-icon">
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" placeholder="密码" name="password" id="password"/>
</div>
</div>
<div class="form-group">
<label class="control-label">昵称</label>
<div class="input-icon">
<input class="form-control placeholder-no-fix" type="text" autocomplete="off" placeholder="输入昵称" name="nickName" id="nickName"/>
</div>
</div>
<div class="form-group">
<label class="control-label">性别</label>
<div class="input-icon">
<input class="form-control placeholder-no-fix" type="text" autocomplete="off" placeholder="输入性别,1为男,2为女" name="gender" id="gender"/>
</div>
</div>
<div class="form-actions" style="text-align:center;padding-top:20px;">
<button id="registerBtn" type="submit" class="btn btn-warning" style="width:200px;">
注册
</button>
</div>
</form>
<script type="text/javascript">
jQuery(document).ready(function() {
$("#registerBtn").on("click",function(){
var telphone=$("#telphone").val();
var password=$("#password").val();
var nickName=$("#nickName").val();
var gender=$("#gender").val();
$.ajax({
type:"POST",
contentType:"application/json;charset=utf-8",
url:"/user/register",
data:JSON.stringify({
"telphone":telphone,
"password":password,
"nickName":nickName,
"gender":gender
}),
success:function(data){
if(data.status == "success"){
alert("注册成功");
window.location.href="/static/login.html";
}else{
alert("请求失败,原因为"+data.data.errMsg);
}
},
error:function(data){
alert("网络请求失败,原因为"+data.responseText);
}
});
return false;
});
});
</script>
后端:请求参数如下
public class RegisterReq {
@NotBlank(message = "手机号不能为空")
private String telphone;
@NotBlank(message = "密码不能为空")
private String password;
@NotBlank(message = "昵称不能为空")
private String nickName;
@NotNull(message = "性别不能为空")
private Integer gender;
public String getTelphone() {
return telphone;
}
public void setTelphone(String telphone) {
this.telphone = telphone;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
}
后端请求处理:
@RequestMapping("/register")
@ResponseBody
public CommonRes register(@Valid @RequestBody RegisterReq registerReq, BindingResult bindingResult) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
if(bindingResult.hasErrors()){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, CommonUtil.processErrorString(bindingResult));
}
UserModel registerUser = new UserModel();
registerUser.setTelphone(registerReq.getTelphone());
registerUser.setPassword(registerReq.getPassword());
registerUser.setNickName(registerReq.getNickName());
registerUser.setGender(registerReq.getGender());
UserModel resUserModel = userService.register(registerUser);
return CommonRes.create(resUserModel);
}
用户登陆功能:
前端:
传入两个参数 电话号码和密码
<script type="text/javascript">
jQuery(document).ready(function() {
$("#registerBtn").on("click",function(){
window.location.href="/static/register.html";
return false;
});
$("#loginBtn").on("click",function(){
var telphone=$("#telphone").val();
var password=$("#password").val();
$.ajax({
type:"POST",
contentType:"application/json;charset=utf-8",
url:"/user/login",
data:JSON.stringify({
"telphone":telphone,
"password":password
}),
success:function(data){
if(data.status == "success"){
window.location.href="/static/index.html";
}else{
alert("请求失败,原因为"+data.data.errMsg);
}
},
error:function(data){
alert("网络请求失败,原因为"+data.responseText);
}
});
return false;
});
});
</script>
登陆请求参数
public class LoginReq {
@NotBlank(message = "手机号不能为空")
private String telphone;
@NotBlank(message = "密码不能为空")
private String password;
public String getTelphone() {
return telphone;
}
public void setTelphone(String telphone) {
this.telphone = telphone;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
登陆请求处理:
@RequestMapping("/login")
@ResponseBody
public CommonRes login(@RequestBody @Valid LoginReq loginReq,BindingResult bindingResult) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
if(bindingResult.hasErrors()){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,CommonUtil.processErrorString(bindingResult));
}
UserModel userModel = userService.login(loginReq.getTelphone(),loginReq.getPassword());
httpServletRequest.getSession().setAttribute(CURRENT_USER_SESSION,userModel);
return CommonRes.create(userModel);
}
获取当前用户信息:
//获取当前用户信息
@RequestMapping("/getcurrentuser")
@ResponseBody
public CommonRes getCurrentUser(){
UserModel userModel = (UserModel) httpServletRequest.getSession().getAttribute(CURRENT_USER_SESSION);
return CommonRes.create(userModel);
}
通过id得到用户信息:
@RequestMapping("/get")
@ResponseBody
public CommonRes getUser(@RequestParam(name="id")Integer id) throws BusinessException {
UserModel userModel = userService.getUser(id);
if(userModel == null){
//return CommonRes.create(new CommonError(EmBusinessError.NO_OBJECT_FOUND),"fail");
throw new BusinessException(EmBusinessError.NO_OBJECT_FOUND);
}else{
return CommonRes.create(userModel);
}
}
前端获取用户信息:
//获取当前用户的信息
$.ajax({
type:"POST",
contentType:"application/json;charset=utf-8",
url:"/user/getcurrentuser",
success:function(data){
if(data.status == "success"){
if(data.data == null){
g_currentUser = null;
}else{
g_currentUser = data.data;
}
if(g_currentUser == null){
$("#rightTitle").text("登录");
}else{
$("#rightTitle").text("注销");
}
}else{
alert("请求失败,原因为"+data.data.errMsg);
}
},
error:function(data){
alert("网络请求失败,原因为"+data.responseText);
}
});
登出处理
@RequestMapping("/logout")
@ResponseBody
public CommonRes logout() throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
httpServletRequest.getSession().invalidate();
return CommonRes.create(null);
}
管理员登陆
前端:
<form class="login-form">
<div class="form-group">
<label class="control-label">手机号</label>
<div class="input-icon">
<input class="form-control placeholder-no-fix" type="text" autocomplete="off" placeholder="输入手机号" name="telphone" id="telphone"/>
</div>
</div>
<div class="form-group">
<label class="control-label">密码</label>
<div class="input-icon">
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" placeholder="密码" name="password" id="password"/>
</div>
</div>
<div class="form-actions" style="text-align:center;padding-top:20px;">
<button id="loginBtn" type="submit" class="btn btn-warning" style="width:200px;">
登陆
</button>
</div>
<div class="form-actions" style="text-align:center;padding-top:20px;">
<button id="registerBtn" type="submit" class="btn btn-warning" style="width:200px;">
注册
</button>
</div>
</form>
$.ajax( {
url:'/admin/admin/login',// 跳转到 action
data:$('.login-form').serialize(),
type:'POST',
processData:true,
contentType:"application/x-www-form-urlencoded",
success:function(data) {
alert(data.status);
if(data.status=="success"){
location.href = "/admin/index/index";
}else if(data.status=="fail"){
alert(data.data.errMessage);
}
},
error : function(e) {
// view("异常!");
alert(e);
}
});
后端判断:
@RequestMapping(value = "/login",method = RequestMethod.POST)
public String login(@RequestParam(name="email")String email,
@RequestParam(name="password")String password ) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
if (StringUtils.isEmpty(email) || StringUtils.isEmpty(password)) {
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "用户名密码不能为空");
}
if(email.equals(this.email) && encodeByMd5(password).equals(this.encrptyPassord)){
//登录成功
httpServletRequest.getSession().setAttribute(CURRENT_ADMIN_SESSION,email);
return "redirect:/admin/admin/index";
}else{
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"用户名密码错误");
}
}
登陆后直接跳转到首页:
@RequestMapping("/index")
public ModelAndView index(){
String userName = "imooc";
ModelAndView modelAndView = new ModelAndView("/index.html");
modelAndView.addObject("name",userName);
return modelAndView;
}
AOP切面编程,对非法访问进行拦截
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AdminPermission {
String produceType() default "text/html";
}
@Aspect
@Configuration
public class ControllerAspect {
@Autowired
private HttpServletRequest httpServletRequest;
@Autowired
private HttpServletResponse httpServletResponse;
@Around("execution(* com.imooc.dianping.controller.admin.*.*(..)) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")
public Object adminControllerBeforeValidation(ProceedingJoinPoint joinPoint) throws Throwable {
Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();
//获取方法是否有AdminPermission标注
AdminPermission adminPermission = method.getAnnotation(AdminPermission.class);
if(adminPermission == null){
//公共方法
Object resultObject = joinPoint.proceed();
return resultObject;
}
//判断当前管理员是否登录
String email = (String) httpServletRequest.getSession().getAttribute(AdminController.CURRENT_ADMIN_SESSION);
if(email == null){
if(adminPermission.produceType().equals("text/html")){
httpServletResponse.sendRedirect("/admin/admin/loginpage");
return null;
}else{
CommonError commonError= new CommonError(EmBusinessError.ADMIN_SHOULD_LOGIN);
return CommonRes.create(commonError,"fail");
}
}else{
Object resultObject = joinPoint.proceed();
return resultObject;
}
}
}
管理员首页:
功能主要是获取注册用户,商户,商品和门店的数量
@RequestMapping("/index")
@AdminPermission
public ModelAndView index(){
ModelAndView modelAndView = new ModelAndView("/admin/admin/index");
modelAndView.addObject("userCount",userService.countAllUser());
modelAndView.addObject("shopCount",shopService.countAllShop());
modelAndView.addObject("categoryCount",categoryService.countAllCategory());
modelAndView.addObject("sellerCount",sellerService.countAllSeller());
modelAndView.addObject("CONTROLLER_NAME","admin");
modelAndView.addObject("ACTION_NAME","index");
return modelAndView;
}
<div class="number" th:text="${userCount}">
商户模块:
商户查询功能:
//商户列表
@RequestMapping("/index")
@AdminPermission
public ModelAndView index(PageQuery pageQuery){
PageHelper.startPage(pageQuery.getPage(),pageQuery.getSize());
List<SellerModel> sellerModelList = sellerService.selectAll();
PageInfo<SellerModel> sellerModelPageInfo = new PageInfo<>(sellerModelList);
ModelAndView modelAndView = new ModelAndView("/admin/seller/index.html");
modelAndView.addObject("data",sellerModelPageInfo);
modelAndView.addObject("CONTROLLER_NAME","seller");
modelAndView.addObject("ACTION_NAME","index");
return modelAndView;
}
<tr th:each="seller:${data.list}">
<td th:text="${seller.id}"></td>
<td th:text="${seller.name}"></td>
<td th:text="${seller.remarkScore}"></td>
<td th:text="${seller.disabledFlag}"></td>
<td>
<a th:style="(${seller.disabledFlag}==0) ?'display:none'" href="#" th:id="'up'+${seller.id}" th:attr="data-id=${seller.id}" class="btn default btn-xs blue">启用</a>
<a th:style="(${seller.disabledFlag}==1) ?'display:none'" href="#" th:id="'down'+${seller.id}" th:attr="data-id=${seller.id}" class="btn default btn-xs red">禁用</a>
</td>
</tr>
添加商户功能:
@RequestMapping(value = "/create",method = RequestMethod.POST)
@AdminPermission
public String create(@Valid SellerCreateReq sellerCreateReq, BindingResult bindingResult) throws BusinessException {
if(bindingResult.hasErrors()){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, CommonUtil.processErrorString(bindingResult));
}
SellerModel sellerModel = new SellerModel();
sellerModel.setName(sellerCreateReq.getName());
sellerService.create(sellerModel);
return "redirect:/admin/seller/index";
}
<form action="/admin/seller/create" id="create" class="form-horizontal form-row-seperated" method="post">
<div class="form-body">
<div class="form-group">
<label class="col-md-3 control-label">商户名<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="name" id="name" value="" class="form-control" />
</div>
</div>
</div>
<div class="form-actions fluid nobg">
<div class="col-md-offset-3 col-md-9">
<button type="submit" class="btn yellow-lemon" id="saveButton"><i class="fa fa-check"></i> 创建 </button>
<button type="button" class="btn default" style="margin-left:12px;" onclick = "javascript:history.go(-1)"> 取消 </button>
</div>
</div>
</form>
商户的启用和禁用功能:
$("a[id^='down']").on('click',function(){
var res = window.confirm("确认要禁用商户吗?");
if(!res){
return;
}
var id = $(this).data("id");
$.ajax({
type : "POST",
contentType : "application/x-www-form-urlencoded",
url : "/admin/seller/down",
data: {
"id": id,
},
success : function(data){
if(data.status == 'success'){
alert("禁用商户成功");
window.location.href = "/admin/seller/index";
}else{
alert("禁用商户失败,原因为"+data.data.errMsg);
}
},
error : function(data){
alert("禁用商户失败,原因为"+data.responseText);
}
});
});
$("a[id^='up']").on('click',function(){
var res = window.confirm("确认要启用商户吗?");
if(!res){
return;
}
var id = $(this).data("id");
$.ajax({
type : "POST",
contentType : "application/x-www-form-urlencoded",
url : "/admin/seller/up",
data: {
"id": id,
},
success : function(data){
if(data.status == 'success'){
alert("启用商户成功");
window.location.href = "/admin/seller/index";
}else{
alert("启用商户失败,原因为"+data.data.errMsg);
}
},
error : function(data){
alert("启用商户失败,原因为"+data.responseText);
}
});
});
@RequestMapping(value="down",method = RequestMethod.POST)
@AdminPermission
@ResponseBody
public CommonRes down(@RequestParam(value="id")Integer id) throws BusinessException {
SellerModel sellerModel = sellerService.changeStatus(id,1);
return CommonRes.create(sellerModel);
}
@RequestMapping(value="up",method = RequestMethod.POST)
@AdminPermission
@ResponseBody
public CommonRes up(@RequestParam(value="id")Integer id) throws BusinessException {
SellerModel sellerModel = sellerService.changeStatus(id,0);
return CommonRes.create(sellerModel);
}
门店模块:
门店查询功能:
//门店列表
@RequestMapping("/index")
@AdminPermission
public ModelAndView index(PageQuery pageQuery){
PageHelper.startPage(pageQuery.getPage(),pageQuery.getSize());
List<ShopModel> shopModelList = shopService.selectAll();
PageInfo<ShopModel> shopModelPageInfo = new PageInfo<>(shopModelList);
ModelAndView modelAndView = new ModelAndView("/admin/shop/index.html");
modelAndView.addObject("data",shopModelPageInfo);
modelAndView.addObject("CONTROLLER_NAME","shop");
modelAndView.addObject("ACTION_NAME","index");
return modelAndView;
}
<table class="table table-striped table-hover">
<thead>
<tr>
<th>id</th>
<th>图标</th>
<th>门店名</th>
<th>评分</th>
<th>人均价格</th>
<th>品类信息</th>
<th>标签</th>
<th>开始营业时间</th>
<th>结束营业时间</th>
<th>地址</th>
<th>商家信息</th>
</tr>
</thead>
<tbody>
<tr th:each="shop:${data.list}">
<td th:text="${shop.id}"></td>
<td><img style="width:40px;height:40px;" th:src="${shop.iconUrl}"/></td>
<td th:text="${shop.name}"></td>
<td th:text="${shop.remarkScore}"</td>
<td th:text="${shop.pricePerMan}"</td>
<td th:text="${shop.categoryModel.name}"></td>
<td th:text="${shop.tags}"></td>
<td th:text="${shop.startTime}"></td>
<td th:text="${shop.endTime}"></td>
<td th:text="${shop.address}"></td>
<td th:text="${shop.sellerModel.name}"></td>
</tr>
</tbody>
</table>
门店添加功能:
这里有个bug,图片只有路径,不能上传成功,无法正确显示
<form action="/admin/shop/create" id="create" class="form-horizontal form-row-seperated" method="post">
<div class="form-body">
<div class="form-group">
<label class="col-md-3 control-label">门店icon图片路径<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="iconUrl" id="iconUrl" value="" class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">门店名<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="name" id="name" value="" class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">人均价格<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="pricePerMan" id="pricePerMan" value="" class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">地址<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="address" id="address" value="" class="form-control" />
</div>
<button type="button" id="analyze" class="btn default" style="margin-left:12px;">解析经纬度</button>
</div>
<div class="form-group">
<label class="col-md-3 control-label">经度<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="longitude" id="longitude" value="" readonly class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">纬度<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="latitude" id="latitude" value="" readonly class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">品类ID<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="categoryId" id="categoryId" value="" class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">标签<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="tags" id="tags" value="" class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">开始营业时间(格式08:00)<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="startTime" id="startTime" value="" class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">结束营业时间(格式22:00)<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="endTime" id="endTime" value="" class="form-control" />
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">商家ID<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="sellerId" id="sellerId" value="" class="form-control" />
</div>
</div>
</div>
<div class="form-actions fluid nobg">
<div class="col-md-offset-3 col-md-9">
<button type="submit" class="btn yellow-lemon" id="saveButton"><i class="fa fa-check"></i> 创建 </button>
<button type="button" class="btn default" style="margin-left:12px;" onclick = "javascript:history.go(-1)"> 取消 </button>
</div>
</div>
</form>
@RequestMapping(value = "/create",method = RequestMethod.POST)
@AdminPermission
public String create(@Valid SellerCreateReq sellerCreateReq, BindingResult bindingResult) throws BusinessException {
if(bindingResult.hasErrors()){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, CommonUtil.processErrorString(bindingResult));
}
SellerModel sellerModel = new SellerModel();
sellerModel.setName(sellerCreateReq.getName());
sellerService.create(sellerModel);
return "redirect:/admin/seller/index";
}
门店根据位置名称解析经纬度
给百度发送http请求获取经纬度
$("#analyze").on("click",function(){
$.ajax({
type : "GET",
url : "http://api.map.baidu.com/geocoding/v3/",
data:"address="+encodeURIComponent($("#address").val())+"&output=json&ak=rXLqPGsQnHX4Wt5bn30aBlNfFisImkmS",
dataType:"jsonp",
jsonp:"callback",
jsonpCallback:"showLocation",
success : function(data){
if(data.status == 0){
alert("地址解析成功");
$("#latitude").val(getFloat(data.result.location.lat,6));
$("#longitude").val(getFloat(data.result.location.lng,6));
}else{
alert("获取百度地图失败,原因为"+data);
}
},
error : function(data){
alert("获取百度地图失败,原因为"+data.responseText);
}
});
return false;
});
类目模块:
类目查询功能:
@RequestMapping("/index")
@AdminPermission
public ModelAndView index(PageQuery pageQuery){
PageHelper.startPage(pageQuery.getPage(),pageQuery.getSize());
List<CategoryModel> categoryModelList = categoryService.selectAll();
PageInfo<CategoryModel> categoryModelPageInfo = new PageInfo<>(categoryModelList);
ModelAndView modelAndView = new ModelAndView("/admin/category/index.html");
modelAndView.addObject("data",categoryModelPageInfo);
modelAndView.addObject("CONTROLLER_NAME","category");
modelAndView.addObject("ACTION_NAME","index");
return modelAndView;
}
<table class="table table-striped table-hover">
<thead>
<tr>
<th>id</th>
<th>品类名</th>
<th>icon图片</th>
<th>排序权重</th>
</tr>
</thead>
<tbody>
<tr th:each="category:${data.list}">
<td th:text="${category.id}"></td>
<td th:text="${category.name}"></td>
<td><img style="width:60px;height:60px;" th:src="${category.iconUrl}"/></td>
<td th:text="${category.sort}"></td>
</tr>
</tbody>
</table>
类目创建功能:
这里的图片同样有问题
@RequestMapping(value = "/create",method = RequestMethod.POST)
@AdminPermission
public String create(@Valid CategoryCreateReq categoryCreateReq, BindingResult bindingResult) throws BusinessException {
if(bindingResult.hasErrors()){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, CommonUtil.processErrorString(bindingResult));
}
CategoryModel categoryModel = new CategoryModel();
categoryModel.setName(categoryCreateReq.getName());
categoryModel.setIconUrl(categoryCreateReq.getIconUrl());
categoryModel.setSort(categoryCreateReq.getSort());
categoryService.create(categoryModel);
return "redirect:/admin/category/index";
}
<form action="/admin/category/create" id="create" class="form-horizontal form-row-seperated" method="post">
<div class="form-body">
<div class="form-group">
<label class="col-md-3 control-label">品类名<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="name" id="name" value="" class="form-control" />
</div>
</div>
</div>
<div class="form-body">
<div class="form-group">
<label class="col-md-3 control-label">图片url路径<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="iconUrl" id="iconUrl" value="" class="form-control" />
</div>
</div>
</div>
<div class="form-body">
<div class="form-group">
<label class="col-md-3 control-label">权重<span class="required" aria-required="true"></span></label>
<div class="col-md-6">
<input type="text" name="sort" id="sort" value="" class="form-control" />
</div>
</div>
</div>
<div class="form-actions fluid nobg">
<div class="col-md-offset-3 col-md-9">
<button type="submit" class="btn yellow-lemon" id="saveButton"><i class="fa fa-check"></i> 创建 </button>
<button type="button" class="btn default" style="margin-left:12px;" onclick = "javascript:history.go(-1)"> 取消 </button>
</div>
</div>
</form>
Elasticsearch基础
创建索引
#结构化创建
PUT /employee/
{
"settings" : {
"number_of_shards" : 1,
"number_of_replicas" : 1
},
"mappings" : {
"properties" : {
"name" : { "type" : "text" },
"age" : { "type" : "integer" }
}
}
}
#创建时指定所使用的分词器
PUT /employee=
{
"settings" : {
"number_of_shards" : 1,
"number_of_replicas" : 1
},
"mappings" : {
"properties" : {
"name" : { "type" : "text","analyzer": "english"},
"age" : {"type":"integer"}
}
}
}
#创建索引movie
PUT /movie
{
"settings" : {
"number_of_shards" : 1,
"number_of_replicas" : 1
},
"mappings": {
"properties": {
"title":{"type":"text","analyzer": "english"},
"tagline":{"type":"text","analyzer": "english"},
"release_date":{"type":"date", "format": "8yyyy/MM/dd||yyyy/M/dd||yyyy/MM/d||yyyy/M/d"},
"popularity":{"type":"double"},
"cast":{
"type":"object",
"properties":{
"character":{"type":"text","analyzer":"standard"},
"name":{"type":"text","analyzer":"standard"}
}
},
"overview":{"type":"text","analyzer": "english"}
}
}
}
es查询
#主键查询 GET /employee/_doc/1
#查询所有
GET /employee/_search
{
"query":{
"match_all": {}
}
}
#分页查询
GET /employee/_search
{
"query":{
"match_all": {}
},
"from":1,
"size":1
}
复杂查询
#带条件
GET /employee/_search
{
"query":{
"match": {"name":"ES"}
}
}
#带排序
GET /employee/_search
{
"query":{
"match": {"name":"ES"}
},
"sort":[
{"age":{"order":"desc"}}
]
}
#带聚合
GET /employee/_search
{
"query":{
"match": {"name":"ES"}
},
"sort":[
{"age":{"order":"desc"}}
],
"aggs":{
"group_by_age":{
"terms":{
"field":"age"
}
}
}
}
#match查询,按照字段上定义的分词分析后去索引内查询
GET /movie/_search
{
"query":{
"match":{"title":"steve"}
}
}
#term查询,不进行词的分析,直接去索引查询,及搜索关键词和索引内词的精确匹配
GET /movie/_search
{
"query":{
"match":{"title":"steve zissou"}
}
}
#match分词后的and和or
GET /movie/_search
{
"query":{
"match":{"title":"basketball with cartoom aliens"},
}
}
#使用的是or
GET /movie/_search
{
"query":{
"match": {
"title": {
"query": "basketball with cartoom aliens",
"operator": "and"
}
}
}
}
使用and
#最小词项匹配
GET /movie/_search
{
"query":{
"match": {
"title": {
"query": "basketball with cartoom aliens",
"operator": "or" ,
"minimum_should_match": 2
}
}
}
}
#短语查询
GET /movie/_search
{
"query":{
"match_phrase":{"title":"steve zissou"}
}
}
#短语前缀查询
GET /movie/_search
{
"query":{
"match_phrase_prefix":{"title":"steve zis"}
}
}
#多字段查询
GET /movie/_search
{
"query":{
"multi_match":{
"query":"basketball with cartoom aliens",
"field":["title","overview"]
}
}
}
es分词
对一句话进行分词查看
GET /employee/_analyze
{
"field":"name",
"text":"Eating an apple a day & keeps the doctor away"
}
es插入文档
#创建索引,指定id建立索引
PUT /employee/_doc/1
{
"name": "凯杰",
"age": 30
}
#指定id全量修改索引
PUT /employee/_doc/1
{
"name": "凯dsfsf32杰",
"age"
}
#指定_create防止重复创建
POST /employee/_create/1/
{
"name": "凯1213132杰",
"age": 30
}
es更新文档
#指定id部分字断修改
POST employee/_update/1
{
"doc" : {
"name" : "new_name"
}
}
es查询权重,排序
es查询之后进行排序:
#多字段查询权重
GET /movie/_search
{
"query":{
"multi_match":{
"query":"basketball with cartoom aliens",
"fields":["title^10","overview"],
"tie_break":0.3
}
}
}
#best_fields是以匹配分数最高的字段为准 most_fields 是将所有字段匹配的分数相加
GET /movie/_validate/query?explain
{
//"explain": true,
"query":{
"multi_match":{
"query":"steve job",
"fields":["title","overview"],
"operator": "or",
"type":"best_fields"
}
}
}
#cross_fields:以分词为单位计算栏位总分
GET /movie/_validate/query?explain
{
//"explain": true,
"query":{
"multi_match":{
"query":"steve job",
"fields":["title","overview"],
"operator": "or",
"type":"most_fields"
}
}
}
#dis_max是以匹配分数最高的为权重,同时将其他字段乘以tie_break(0.3)相加作为这一个文档的分数
GET /movie/_search
{
"query":{
"dis_max": {
"queries": [
{ "match": { "title":"basketball with cartoom aliens"}},
{ "match": { "overview":"basketball with cartoom aliens"}}
],
"tie_breaker": 0.3
}
}
}
#filter查询,filter和must类似,但只影响召回,不影响排序,must会影响召回和排序
GET /movie/_search
{
"query":{
"bool":{
"filter":{
"term":{"title":"steve"}
}
}
}
}
#function score自定义打分
GET /movie/_search
{
"query":{
"function_score": {
//原始查询得到oldscore
"query": {
"multi_match":{
"query":"steve job",
"fields":["title","overview"],
"operator": "or",
"type":"most_fields"
}
},
"functions": [
{"field_value_factor": {
"field": "popularity", //对应要处理的字段
"modifier": "log2p", //将字段值+2后,计算对数
"factor": 10 //字段预处理*10
}
}
],
"score_mode": "sum", //不同的field_value_factor之间的得分相加
"boost_mode": "sum" //functions和function_score相加
}
}
}