02.商品分类选择-分析-前端js_
03.商品分类选择-分析-数据库_
(JJTree渲染过程解析(parent_id为0就是父节点,is_parent为1说明下面有子节点,state1正常2删除。tree组件有ztree,异步控件树每个节点都有id,展开节点向服务端发送请求,请求检索子节点列表,参数当前节点的id,服务端响应json数据,)&)
04.商品分类选择-Service_
05.商品分类选型实现_
(使用@RequestParam获取参数(@RequestParam(name=”id”,defaultValue=”0” )第一次请求不带参数,给一个默认值确保肯定有值)&)
06.图片上传分析及图片服务器配置_
(Socket选项 HTTP服务器(开启虚拟机,选择已移动该虚拟机保留原来网路配置不发生变化,复制重新生成网卡原来配置不生效,如果要使用虚拟机通过设置为NAT模式,并设置子网网段)&高可用的分布式文件系统构建(只有一个工程把图片放在工程目录下,在1000并发的时候到达tomcat集群,通过Nginx转发每一个tomcat部署一个应用程序,通过轮询把请求平均分给不同服务器,为了能够保证在不同服务器都能找到目标图片需要专门有一个分布式文件服务器FastDFS(软件分布式文件系统,允许横向扩容与负载均衡保证高性能与高可用)负责图片存放与http图片访问(http服务器可以使tomcat或者是nginx(用于访问静态资源性能较好)))&Nginx 安装及负载均衡配置&)
07.FastDFS上传图片测试_
(跟踪服务器配置(fastDFS没法从中央仓库获取,通过maven工程导入,)&存储节点配置(创建一个资源文件client.conf 配置fastDFS中央仓库服务器地址,后缀与源数据详情)&上传文件测试&)
08.FastDFSClient的使用_
(加载资源文件中的图片(this.getClass.getResource(“/”).getPath()取完还是绝对路径,使用全路径复制会有隐藏字符需要去除格式即可。不以’/'开头时,默认是从此类所在的包下取资源,以’/'开头时,则是从ClassPath根下获取。)&)
package testpackage;
public class TestMain {
public static void main(String[] args) {
System.out.println(TestMain.class.getResource(""));
System.out.println(TestMain.class.getResource("/"));
}
}
file:/E:/workspace/Test/bin/testpackage/
file:/E:/workspace/Test/bin/
上面说到的【path以’/'开头时,则是从ClassPath根下获取;】在这里就是相当于bin目录(Eclipse环境下)。
如果我们想在TestMain.java中分别取到1~3.properties文件,该怎么写路径呢?代码如下:
package testpackage;
public class TestMain {
public static void main(String[] args) {
// 当前类(class)所在的包目录
System.out.println(TestMain.class.getResource(""));
// class path根目录
System.out.println(TestMain.class.getResource("/"));
// TestMain.class在<bin>/testpackage包中
// 2.properties 在<bin>/testpackage包中
System.out.println(TestMain.class.getResource("2.properties"));
// TestMain.class在<bin>/testpackage包中
// 3.properties 在<bin>/testpackage.subpackage包中
System.out.println(TestMain.class.getResource("subpackage/3.properties"));
// TestMain.class在<bin>/testpackage包中
// 1.properties 在bin目录(class根目录)
System.out.println(TestMain.class.getResource("/1.properties"));
}
}
※Class.getResource和Class.getResourceAsStream在使用时,路径选择上是一样的。
Class.getClassLoader().getResource(String path)
path不能以’/'开头时;
path是从ClassPath根下获取;
还是先看一下下面这段代码的输出:
package testpackage;
public class TestMain {
public static void main(String[] args) {
TestMain t = new TestMain();
System.out.println(t.getClass());
System.out.println(t.getClass().getClassLoader());
System.out.println(t.getClass().getClassLoader().getResource(""));
System.out.println(t.getClass().getClassLoader().getResource("/"));//null
}
}
输出结果:
class testpackage.TestMain
sun.misc.Launcher$AppClassLoader@1fb8ee3
file:/E:/workspace/Test/bin/
null
从结果来看【TestMain.class.getResource("/") == t.getClass().getClassLoader().getResource("")】
如果有同样的Project结构
使用Class.getClassLoader().getResource(String path)可以这么写:
package testpackage;
public class TestMain {
public static void main(String[] args) {
TestMain t = new TestMain();
System.out.println(t.getClass().getClassLoader().getResource(""));
System.out.println(t.getClass().getClassLoader().getResource("1.properties"));
System.out.println(t.getClass().getClassLoader().getResource("testpackage/2.properties"));
System.out.println(t.getClass().getClassLoader().getResource("testpackage/subpackage/3.properties"));
}
}
※Class.getClassLoader().getResource和Class.getClassLoader().getResourceAsStream在使用时,路径选择上也是一样的。
09.图片上传功能分析_
10.图片上传功能实现_
(多文件上传1:使用MultipartHttpServletRequest(springMVC需要把commonsi-fileupload两个jar包加到项目中,前端控制器需要配置多媒体解析器MultipartResolver设置默认编码与最大文件大小,通过MultipartFile接收参数,通过@Value加载配置文件的资源,通过Map返回json数据)&单文件上传3:使用MultipartFile结合实体类&通过IOC容器注入Properties类型&placeholder属性&)
11.上传图片功能测试_
12.解决上传图片浏览器兼容性问题_
(使用jackson在服务端将JSON字符串转换成各种Java数据类型(SpringMvc会把对象转为字符串响应浏览器,直接把Map转为json返回String即可)&)
13.富文本编辑器的使用_
(富文本UEditor(富文本编辑器有UEditor、KindEditor、CKEditor都是纯js开发的)&)
14.商品添加功能分析_
15.商品添加-service_
16.商品添加-完成_
02.工程搭建分析_
03.前台系统工程搭建_
(使用URL Rewrite实现网站伪静态(在web.xml中 url-pattern拦截所有*.html 请求网页伪静态,所有url后缀全部改为html,@RequestMapping(“/index”) 通过index.html进行访问。只访问localhost:8080会默认找welcome-file欢迎页index.html 带html后缀去controller匹配)&)
04.首页展示_
05.首页内容管理-数据库分析_
06.内容服务工程搭建_
07.内容分类查询-service_
08.内容分类列表展示_
(@RequestParam注解(与参数名对不上号,使用@RequestParam(“id” ,defaultValue=””)Integer parentId。使用脚本启动服务Maven build clean tomcat7:run )&)
09.内容分类添加-js分析_
10.内容分类添加-mapper_
11.内容分类添加-service_
12.内容分类添加-完成_
13.内容分类修改、删除-作业_
14.内容添加-功能分析_
15.内容添加-service_
16.内容添加-完成_
17.内容编辑、删除_
01.课程计划
(Redis缓存穿透和雪崩(首页并发量最高,每次都查询数据库压力比较大,通过缓存读取内存数据减轻数据库压力,Reids可以把内容持久化到磁盘数据不会丢,内容不会丢失否则瞬时请求会造成数据库雪崩,Redis缓存同步问题)&)
02.首页大广告位实现分析_
04.首页大广告位实现-表现层_
05.首页大广告-测试_
06.redis的安装及启动_
(gcc的简易用法(编译、参数与连接)(编译环境对c语言编译后为可二进制可执行文件,需要按照gcc编译环境,yum install gcc-c++)&用make进行宏编译&makefile的基本语法与变量&RPM安装(install)&Redis安装和配置(rm -rf * 删除所有安装包 ,rm -rf /user/local/redis* )&Redis客户端命令(tar zxf redis-3.0.0.tar.gz 进行解压缩,C语言编译必须有Makefile文件夹,直接使用make命令编译,编译后进行通过make install进行安装 make install PREFIX=/usr/local/redis到指定目录,进入安装目录的bin文件夹,通过./redis-server启动前端启动模式占用一个终端,通过配置文件cp ~/redis-3.0.0/redis.conf 复制到当前文件夹下,进行后端启动不占端口号,修改daemonize yes即可,通过./redis-server redis.conf 后端启动,通过ps aux|grep redis查看进程判断是否启动。 ./redis-cli默认连接6379端口,客户端通过ping pang检测服务器健康状态,连接其他redis服务 ./redis-cli -h 192.168 -p 6379)&Redis基础配置文件&)
sftp是Secure File Transfer Protocol的缩写,安全文件传送协议。它类似于ftp, 但是它提供一种更为安全的网络的加密方法。
如何进行远程连接,进行文件的上传和下载。
在命令行模式下,输入:
sftp 用户名@ip地址 eg: sftp lzy@202.206.64.33
sftp>
如果登陆远程机器不是为了上传下载文件,而是要修改远程主机上的某些文件。可以
ssh lzy@202.206.64.33 (其实sftp就是ssh 的一个程式。)
sftp> get /var/index.php /home/libai/
这条语句将从远程主机的 /var目录下将 index.php 下载到本地 /home/libai/目录下。
sftp> put /home/libai/downloads/linuxgl.pdf /var/
这条语句将把本地 /home/libai/downloads/目录下的 linuxgl.pdf文件上传至远程主机/var 目录下。
要查看远端机器的一些信息,可以直接使用平时的linux命令
比如:pwd 远端机器的当前路径 cd 改变远端机器的路径 ,ls, rm, mkdir,rmdir 都可以用
要查看本机的一些信息,要在平时的linux命令上,加上l
比如:lpwd 本机当前工作目录 lcd 改变本机的路径, lls ,lrm,lmkdir,lrmdir
要离开sftp,用exit 或quit、 bye 均可。详细情况可以查阅 man sftp.
如果觉得在命令行模式下不太方便,可以 sudo apt-get install gftp。在图形界面下操作就简便多了。
07.redis常用命令复_
(Redis数据结构常用命令(Redis一共提供5种数据类型,String普通key-value Hash一个key对应一个hash集,LIST集合 set集合 zset有序集合。String数据类型 set添加一个值 set str1 12345 get str1 incr str1自增,decr减1,Hash命令hset添加一个key hset hash1 field1 abc hget hash1 field1,ttl str1查看key的有效期-1永久保存,ttl str2 -2key不存在,正数正在倒计时,expire str1 100设置过期时间为100秒,key *查看数据库有多少key)&Redis数据结构——哈希&Redis数据结构——链表(linked-list)&Redis数据结构——集合&Redis数据结构——有序集合&INCRBY、DECRBY:对整数值执行加法操作和减法操作& HSET:为字段设置值&)
08.Jedis的使用方法_
(使用Jedis客户端操作Redis(Java客户端通过Jedis,每次创建都有一个连接耗费资源,通过redis连接池JedisPool 节约资源,jedis.getResource()获取jedis来操作数据库)&)
09.redis的使用方法_
(单线程与多线程客户端(持久化RDB和AOF默认开启RDB快照(当前时刻数据)定期操作磁盘,AOF保存对数据库操作的命令频繁操作磁盘性能下降,数据完整性高一点,可以同时开启。Redis有可能丢数据,Mysql或者Oracle关系型数据库不会丢数据,Redis不适合保存大数据适合存储小数据(单线程的顺次处理单个命令尽快完成,通过集群横向扩容),基于Hadoop的Hbase还有MongoDB支持存储海量数据)&)
10.redis集群架构讲解_
(使用Redis集群实现数据水平化存储(Redis集群没有统一的入口,可以连接任何客户端进入集群,集群内部客户端可以相互通讯,检测检点的监控状态通过投票容错实现,redis集群有0-16383个slot为了均匀分布key到不同服务器,每个节点分配一定数量的槽,一般集群分布在3个节点上,每个集群主从同步槽挂了包装高可用,需要6台服务器(一台服务器运行在不同端口6个实例,搭建集群要把dump.rdb快照文件删除,修改redis.conf改变端口号,/cluster-enabled yes集群节点。通过批处理批量执行启动命令 vim start-all.sh cd redis01 ./redis-server redis.conf) cd.. 通过chmod +x start-all.sh增加可执行权限,TCC最大权限 ,./start-all.sh执行)&对文章进行投票&Redis集群容错&Redis集群中的主从复制&Redis主从复制模式&)
11.redis集群搭建01_
(Redis主从架构的缺点&Redis哨兵模式& Redis集群架构& Redis集群环境搭建&mongodump 和mongorestore&批处理和任务&权限设置&)
12.redis集群搭建02_
(RPM、SRPM与YUM&)
13.使用redis-cli连接集群_
14.使用JedisCluster连接集群_
(使用Jedis客户端操作Redis(Java通过JedisCluster连接到集群,自带连接池,构造参数是set类型集合每个元素是HostAndPort类型)&)
15.JedisClient连接单机版_
(使用Annotation注解法创建对象(<context:component-scan base-package=””>注解既包括了开启注解<context:annotation-config>也包括了扫描包)&组件扫描注解&)
16.jedisClient连接集群_
17.向业务逻辑中添加缓存_
18.添加缓存测试_
19.缓存同步处理_
(消息发送和同步接收&HDEL:删除字段&)
day06
01.课程计划_
02.solr服务搭建_
(catalina.sh脚本&Redis基础配置文件&Tomcat启动&复制、删除与移动:cp、rm、mv &配置web.xml文件&)
03.业务域的定义_
(中文分词安装&IK分词器安装&内部类——InnerClasses属性 &基于XML Schema的简化配置方式&使用th:field属性&语言区域&使用服务提供业务逻辑&)
04.业务数据sql语句编写_
05.搜索工程搭建_
(覆盖起步依赖引入的传递依赖&)
06.导入商品数据到索引库-dao_
07.solrj实现索引库维护_
(在Sping Boot中集成Solr,实现数据的增、删、改和查&)
08.导入商品数据-Service_
( constructor方法&)
09.导入商品数据-jsp_
10.商品数据导入成功_
11.首页跳转到搜索页面_
12.商品实现分析_
13.使用solrJ查询索引库_
(Solr——搜索应用服务器&)
14.搜索服务-dao实现_
day07
01.课程计划_
02.商品搜索功能-Service_
03.商品搜索功能-Controller_
04.搜索功能测试_
05.什么是SolrCloud_
06.solr集群架构讲解_
(并发&分片简介&)
07.zookeeper集群讲解_
08.zookeeper集群搭建_
(配置ZooKeeper集群&Data Server简介&修改文件时间或创建新文件:touch&变量的使用与设置:echo、变量设置规则、unset &vim的额外功能&)
09.solr集群的配置_
10.SolrCloud中管理Collection_
11.闲扯_
12.使用SolrJ管理SolrCloud_
13.搜索功能切换到集群_
14.全局异常处理器的应用_
day08
01.课程计划_
02.同步索引库功能分析_
03.什么是ActiveMQ_
04.activemq的安装_
(vim的额外功能&)
05.Activemq发送queue消息_
(Topic 和 Queue&)
06.接收queue消息_
07.发送topic消息_
08.接收topic消息_
09.spring整合Activemq_
(使用JmsTemplate 发送&)
10.使用JMSTemplate发送消息_
11.Activemq整合Spring接收消息_
12.添加商品同步索引库-发送消息_
13.添加商品同步索引库-mapper_
14.添加商品同步索引库-MessageListener_
15.添加商品同步索引库-测试_
16.小结_
day09
01.课程计划_
02.商品详情页面工程搭建_
03.商品详情页面展示分析_
04.商品详情页面展示-代码实现_
05.商品详情页面展示-测试_
06.商品详情页面添加缓存分析_
07.redis添加缓存的使用方法_
08.向业务逻辑中添加缓存_
09.添加缓存测试_
10.freemarker的使用方法_
11.freemarker语法-取pojo的属性_
12.freemarker语法-list_
13.freemarker语法-if_
14.freemarker语法-日期类型处理_
15freemarker语法-null值的处理_
16.freemarker语法-include_
17.freemarker整合Spring_
18.网页静态化方案分析_
19.网页静态化-freemarker模板改造_
20.网页静态化-业务逻辑_
21.网页静态化-测试_
day10
01.课程计划_
(构建HTTP服务器&)
02.什么是nginx_
03.nginx的应用场景_
04.nginx的安装及启动_
( v-pre&)
05.nginx的配置文件介绍_
06.通过端口区分虚拟主机_
(shift&使用fetchType属性设置局部加载策略&ngx_http_upstream_t结构体&)
07.什么是域名及hosts文件的作用_
08.通过域名区分虚拟主机_
09.使用nginx配置反向代理_
(proxy_pass请求代理规则&)
10.使用nginx实现负载均衡_
11.nginx小结_
12.keepalived+nginx实现高可用_
13.lvs实现高并发处理_
14.sso系统分析_
15.sso工程搭建_
16.sso系统接口分析_
day11_单点登录&js跨域
01.课程计划_
02.检查数据是否可用-接口分析_
03.检查数据是否可用-Service_
04.检查数据是否可用-Controller_
05.用户注册-Service_
06.用户注册-表现层_
07.用户登录流程分析_
08.用户登录-Service_
(使用Redis保存token令牌&全局唯一标识符UUID&)
09.用户登录表现层_
10.用户登录测试_
11.根据token查询用户信息-Service_
(使用Redis保存token令牌&)
12.根据token查询用户信息-表现层层_
13.安全退出-作业_
14.登录、注册页面展示_
15.用户注册页面实现_
16.用户登页面实现_
17.js跨域分析_
(跨域AJAX&)
- jsonp的原理_
(活用模板方法模式及Callback&callback调用&JSONP&media query语法&)
19.jsonp服务端处理_
20.jsonp处理第二种方法_
day12
01.课程计划_
02.购物车实现分析_
03.购物车工程搭建_
04.商品详情页面加入购物车改造_
05.添加购物车功能分析_
06.添加购物车实现_
07.添加购物车测试_
08.展示购物车列表_
09.修改购物车商品数量_
10.修改购物车商品数量测试_
11.删除购物车商品_
12.购物车小结_
13.订单系统工程搭建_
14.订单确认页面展示_
15.登录拦截器实现分析_
(HandlerInterceptor接口&Handler实例&)
16.拦截器业务逻辑实现_
17.拦截器测试及登录成功回调_
(Interceptor&)
18.拦截器测试取用户信息_
19.订单生成-数据库分析_
20.订单生成-页面分析_
day13
01.课程计划_
02.订单提交-分析回顾_
03.生成订单业务逻辑_
04.订单生成表现层_
05.订单生成-测试_
06.系统架构讲解_
07.系统部署规划_
(安装RPM包&)
08.tomcat热部署_
09.系统部署演示_
10.项目总结01_
11.项目总结02_
12.面试中的问题_
部分代码
taotao-manager-web
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.taotao</groupId>
<artifactId>taotao-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.taotao</groupId>
<artifactId>taotao-manager-web</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-manager-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-content-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.taotao</groupId>
<artifactId>taotao-search-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- JSP相关 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- dubbo相关的jar包 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<exclusions>
<exclusion>
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>netty</artifactId>
<groupId>org.jboss.netty</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
</dependency>
<!-- 添加FastDFS客户端的引用 -->
<dependency>
<groupId>fastdfs_client</groupId>
<artifactId>fastdfs_client</artifactId>
<version>1.25</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<!-- 文件上传组件 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<path>/</path>
<port>8081</port>
</configuration>
</plugin>
</plugins>
</build>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>taotao-manager-web</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- post乱码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 前端控制器 -->
<servlet>
<servlet-name>taotao-manager-web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>taotao-manager-web</servlet-name>
<!-- 拦截所有请求jsp除外 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>管理员登录</title>
</head>
<body style="background-color: #F3F3F3">
<div class="easyui-dialog" title="管理员登录" data-options="closable:false,draggable:false" style="width:400px;height:300px;padding:10px;">
<div style="margin-left: 50px;margin-top: 50px;">
<div style="margin-bottom:20px;">
<div>
用户名: <input name="username" class="easyui-textbox" data-options="required:true" style="width:200px;height:32px" value="admin"/>
</div>
</div>
<div style="margin-bottom:20px">
<div>
密 码: <input name="password" class="easyui-textbox" type="password" style="width:200px;height:32px" data-options="" value="admin"/>
</div>
</div>
<div>
<a id="login" class="easyui-linkbutton" iconCls="icon-ok" style="width:100px;height:32px;margin-left: 50px">登录</a>
</div>
</div>
</div>
<script type="text/javascript">
$("#login").click(function(){
var username = $("[name=username]").val();
var password = $("[name=password]").val();
if(username!="admin" || password!="admin"){
$.messager.alert('错误',"用户名密码不正确!");
return ;
}
window.location.href="/rest/page/index";
});
</script>
</body>
</html>
item-param-list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<table class="easyui-datagrid" id="itemParamList" title="商品列表"
data-options="singleSelect:false,collapsible:true,pagination:true,url:'/item/param/list',method:'get',pageSize:30,toolbar:itemParamListToolbar">
<thead>
<tr>
<th data-options="field:'ck',checkbox:true"></th>
<th data-options="field:'id',width:60">ID</th>
<th data-options="field:'itemCatId',width:80">商品类目ID</th>
<th data-options="field:'itemCatName',width:100">商品类目</th>
<th data-options="field:'paramData',width:300,formatter:formatItemParamData">规格(只显示分组名称)</th>
<th data-options="field:'created',width:130,align:'center',formatter:TAOTAO.formatDateTime">创建日期</th>
<th data-options="field:'updated',width:130,align:'center',formatter:TAOTAO.formatDateTime">更新日期</th>
</tr>
</thead>
</table>
<div id="itemEditWindow" class="easyui-window" title="编辑商品" data-options="modal:true,closed:true,iconCls:'icon-save',href:'/item-edit'" style="width:80%;height:80%;padding:10px;">
</div>
<script>
function formatItemParamData(value , index){
var json = JSON.parse(value);
var array = [];
$.each(json,function(i,e){
array.push(e.group);
});
return array.join(",");
}
function getSelectionsIds(){
var itemList = $("#itemParamList");
var sels = itemList.datagrid("getSelections");
var ids = [];
for(var i in sels){
ids.push(sels[i].id);
}
ids = ids.join(",");
return ids;
}
var itemParamListToolbar = [{
text:'新增',
iconCls:'icon-add',
handler:function(){
TAOTAO.createWindow({
url : "/item-param-add",
});
}
},{
text:'编辑',
iconCls:'icon-edit',
handler:function(){
$.messager.alert('提示','该功能未实现!');
}
},{
text:'删除',
iconCls:'icon-cancel',
handler:function(){
var ids = getSelectionsIds();
if(ids.length == 0){
$.messager.alert('提示','未选中商品规格!');
return ;
}
$.messager.confirm('确认','确定删除ID为 '+ids+' 的商品规格吗?',function(r){
if (r){
var params = {"ids":ids};
$.post("/item/param/delete",params, function(data){
if(data.status == 200){
$.messager.alert('提示','删除商品规格成功!',undefined,function(){
$("#itemParamList").datagrid("reload");
});
}
});
}
});
}
}];
</script>
item-param-add.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<table cellpadding="5" style="margin-left: 30px" id="itemParamAddTable" class="itemParam">
<tr>
<td>商品类目:</td>
<td><a href="javascript:void(0)" class="easyui-linkbutton selectItemCat">选择类目</a>
<input type="hidden" name="cid" style="width: 280px;"></input>
</td>
</tr>
<tr class="hide addGroupTr">
<td>规格参数:</td>
<td>
<ul>
<li><a href="javascript:void(0)" class="easyui-linkbutton addGroup">添加分组</a></li>
</ul>
</td>
</tr>
<tr>
<td></td>
<td>
<a href="javascript:void(0)" class="easyui-linkbutton submit">提交</a>
<a href="javascript:void(0)" class="easyui-linkbutton close">关闭</a>
</td>
</tr>
</table>
<div class="itemParamAddTemplate" style="display: none;">
<li class="param">
<ul>
<li>
<input class="easyui-textbox" style="width: 150px;" name="group"/> <a href="javascript:void(0)" class="easyui-linkbutton addParam" title="添加参数" data-options="plain:true,iconCls:'icon-add'"></a>
</li>
<li>
<span>|-------</span><input style="width: 150px;" class="easyui-textbox" name="param"/> <a href="javascript:void(0)" class="easyui-linkbutton delParam" title="删除" data-options="plain:true,iconCls:'icon-cancel'"></a>
</li>
</ul>
</li>
</div>
<script style="text/javascript">
$(function(){
TAOTAO.initItemCat({
fun:function(node){
$(".addGroupTr").hide().find(".param").remove();
// 判断选择的目录是否已经添加过规格
$.getJSON("/item/param/query/itemcatid/" + node.id,function(data){
if(data.status == 200 && data.data){
$.messager.alert("提示", "该类目已经添加,请选择其他类目。", undefined, function(){
$("#itemParamAddTable .selectItemCat").click();
});
return ;
}
$(".addGroupTr").show();
});
}
});
$(".addGroup").click(function(){
var temple = $(".itemParamAddTemplate li").eq(0).clone();
$(this).parent().parent().append(temple);
temple.find(".addParam").click(function(){
var li = $(".itemParamAddTemplate li").eq(2).clone();
li.find(".delParam").click(function(){
$(this).parent().remove();
});
li.appendTo($(this).parentsUntil("ul").parent());
});
temple.find(".delParam").click(function(){
$(this).parent().remove();
});
});
$("#itemParamAddTable .close").click(function(){
$(".panel-tool-close").click();
});
$("#itemParamAddTable .submit").click(function(){
var params = [];
var groups = $("#itemParamAddTable [name=group]");
groups.each(function(i,e){
var p = $(e).parentsUntil("ul").parent().find("[name=param]");
var _ps = [];
p.each(function(_i,_e){
var _val = $(_e).siblings("input").val();
if($.trim(_val).length>0){
_ps.push(_val);
}
});
var _val = $(e).siblings("input").val();
if($.trim(_val).length>0 && _ps.length > 0){
params.push({
"group":_val,
"params":_ps
});
}
});
var url = "/item/param/save/"+$("#itemParamAddTable [name=cid]").val();
$.post(url,{"paramData":JSON.stringify(params)},function(data){
if(data.status == 200){
$.messager.alert('提示','新增商品规格成功!',undefined,function(){
$(".panel-tool-close").click();
$("#itemParamList").datagrid("reload");
});
}
});
});
});
</script>
item-list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<table class="easyui-datagrid" id="itemList" title="商品列表"
data-options="singleSelect:false,collapsible:true,pagination:true,url:'/item/list',method:'get',pageSize:30,toolbar:toolbar">
<thead>
<tr>
<th data-options="field:'ck',checkbox:true"></th>
<th data-options="field:'id',width:60">商品ID</th>
<th data-options="field:'title',width:200">商品标题</th>
<th data-options="field:'cid',width:100">叶子类目</th>
<th data-options="field:'sellPoint',width:100">卖点</th>
<th data-options="field:'price',width:70,align:'right',formatter:TAOTAO.formatPrice">价格</th>
<th data-options="field:'num',width:70,align:'right'">库存数量</th>
<th data-options="field:'barcode',width:100">条形码</th>
<th data-options="field:'status',width:60,align:'center',formatter:TAOTAO.formatItemStatus">状态</th>
<th data-options="field:'created',width:130,align:'center',formatter:TAOTAO.formatDateTime">创建日期</th>
<th data-options="field:'updated',width:130,align:'center',formatter:TAOTAO.formatDateTime">更新日期</th>
</tr>
</thead>
</table>
<div id="itemEditWindow" class="easyui-window" title="编辑商品" data-options="modal:true,closed:true,iconCls:'icon-save',href:'/rest/page/item-edit'" style="width:80%;height:80%;padding:10px;">
</div>
<script>
function getSelectionsIds(){
var itemList = $("#itemList");
var sels = itemList.datagrid("getSelections");
var ids = [];
for(var i in sels){
ids.push(sels[i].id);
}
ids = ids.join(",");
return ids;
}
var toolbar = [{
text:'新增',
iconCls:'icon-add',
handler:function(){
$(".tree-title:contains('新增商品')").parent().click();
}
},{
text:'编辑',
iconCls:'icon-edit',
handler:function(){
var ids = getSelectionsIds();
if(ids.length == 0){
$.messager.alert('提示','必须选择一个商品才能编辑!');
return ;
}
if(ids.indexOf(',') > 0){
$.messager.alert('提示','只能选择一个商品!');
return ;
}
$("#itemEditWindow").window({
onLoad :function(){
//回显数据
var data = $("#itemList").datagrid("getSelections")[0];
data.priceView = TAOTAO.formatPrice(data.price);
$("#itemeEditForm").form("load",data);
// 加载商品描述
$.getJSON('/rest/item/query/item/desc/'+data.id,function(_data){
if(_data.status == 200){
//UM.getEditor('itemeEditDescEditor').setContent(_data.data.itemDesc, false);
itemEditEditor.html(_data.data.itemDesc);
}
});
//加载商品规格
$.getJSON('/rest/item/param/item/query/'+data.id,function(_data){
if(_data && _data.status == 200 && _data.data && _data.data.paramData){
$("#itemeEditForm .params").show();
$("#itemeEditForm [name=itemParams]").val(_data.data.paramData);
$("#itemeEditForm [name=itemParamId]").val(_data.data.id);
//回显商品规格
var paramData = JSON.parse(_data.data.paramData);
var html = "<ul>";
for(var i in paramData){
var pd = paramData[i];
html+="<li><table>";
html+="<tr><td colspan=\"2\" class=\"group\">"+pd.group+"</td></tr>";
for(var j in pd.params){
var ps = pd.params[j];
html+="<tr><td class=\"param\"><span>"+ps.k+"</span>: </td><td><input autocomplete=\"off\" type=\"text\" value='"+ps.v+"'/></td></tr>";
}
html+="</li></table>";
}
html+= "</ul>";
$("#itemeEditForm .params td").eq(1).html(html);
}
});
TAOTAO.init({
"pics" : data.image,
"cid" : data.cid,
fun:function(node){
TAOTAO.changeItemParam(node, "itemeEditForm");
}
});
}
}).window("open");
}
},{
text:'删除',
iconCls:'icon-cancel',
handler:function(){
var ids = getSelectionsIds();
if(ids.length == 0){
$.messager.alert('提示','未选中商品!');
return ;
}
$.messager.confirm('确认','确定删除ID为 '+ids+' 的商品吗?',function(r){
if (r){
var params = {"ids":ids};
$.post("/rest/item/delete",params, function(data){
if(data.status == 200){
$.messager.alert('提示','删除商品成功!',undefined,function(){
$("#itemList").datagrid("reload");
});
}
});
}
});
}
},'-',{
text:'下架',
iconCls:'icon-remove',
handler:function(){
var ids = getSelectionsIds();
if(ids.length == 0){
$.messager.alert('提示','未选中商品!');
return ;
}
$.messager.confirm('确认','确定下架ID为 '+ids+' 的商品吗?',function(r){
if (r){
var params = {"ids":ids};
$.post("/rest/item/instock",params, function(data){
if(data.status == 200){
$.messager.alert('提示','下架商品成功!',undefined,function(){
$("#itemList").datagrid("reload");
});
}
});
}
});
}
},{
text:'上架',
iconCls:'icon-remove',
handler:function(){
var ids = getSelectionsIds();
if(ids.length == 0){
$.messager.alert('提示','未选中商品!');
return ;
}
$.messager.confirm('确认','确定上架ID为 '+ids+' 的商品吗?',function(r){
if (r){
var params = {"ids":ids};
$.post("/rest/item/reshelf",params, function(data){
if(data.status == 200){
$.messager.alert('提示','上架商品成功!',undefined,function(){
$("#itemList").datagrid("reload");
});
}
});
}
});
}
}];
</script>
item-edit.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<link href="/js/kindeditor-4.1.10/themes/default/default.css" type="text/css" rel="stylesheet">
<script type="text/javascript" charset="utf-8" src="/js/kindeditor-4.1.10/kindeditor-all-min.js"></script>
<script type="text/javascript" charset="utf-8" src="/js/kindeditor-4.1.10/lang/zh_CN.js"></script>
<div style="padding:10px 10px 10px 10px">
<form id="itemeEditForm" class="itemForm" method="post">
<input type="hidden" name="id"/>
<table cellpadding="5">
<tr>
<td>商品类目:</td>
<td>
<a href="javascript:void(0)" class="easyui-linkbutton selectItemCat">选择类目</a>
<input type="hidden" name="cid" style="width: 280px;"></input>
</td>
</tr>
<tr>
<td>商品标题:</td>
<td><input class="easyui-textbox" type="text" name="title" data-options="required:true" style="width: 280px;"></input></td>
</tr>
<tr>
<td>商品卖点:</td>
<td><input class="easyui-textbox" name="sellPoint" data-options="multiline:true,validType:'length[0,150]'" style="height:60px;width: 280px;"></input></td>
</tr>
<tr>
<td>商品价格:</td>
<td><input class="easyui-numberbox" type="text" name="priceView" data-options="min:1,max:99999999,precision:2,required:true" />
<input type="hidden" name="price"/>
</td>
</tr>
<tr>
<td>库存数量:</td>
<td><input class="easyui-numberbox" type="text" name="num" data-options="min:1,max:99999999,precision:0,required:true" /></td>
</tr>
<tr>
<td>条形码:</td>
<td>
<input class="easyui-textbox" type="text" name="barcode" data-options="validType:'length[1,30]'" />
</td>
</tr>
<tr>
<td>商品图片:</td>
<td>
<a href="javascript:void(0)" class="easyui-linkbutton picFileUpload">上传图片</a>
<input type="hidden" name="image"/>
</td>
</tr>
<tr>
<td>商品描述:</td>
<td>
<textarea style="width:800px;height:300px;visibility:hidden;" name="desc"></textarea>
</td>
</tr>
<tr class="params hide">
<td>商品规格:</td>
<td>
</td>
</tr>
</table>
<input type="hidden" name="itemParams"/>
<input type="hidden" name="itemParamId"/>
</form>
<div style="padding:5px">
<a href="javascript:void(0)" class="easyui-linkbutton" onclick="submitForm()">提交</a>
</div>
</div>
<script type="text/javascript">
var itemEditEditor ;
$(function(){
//实例化编辑器
itemEditEditor = TAOTAO.createEditor("#itemeEditForm [name=desc]");
});
function submitForm(){
if(!$('#itemeEditForm').form('validate')){
$.messager.alert('提示','表单还未填写完成!');
return ;
}
$("#itemeEditForm [name=price]").val(eval($("#itemeEditForm [name=priceView]").val()) * 1000);
itemEditEditor.sync();
var paramJson = [];
$("#itemeEditForm .params li").each(function(i,e){
var trs = $(e).find("tr");
var group = trs.eq(0).text();
var ps = [];
for(var i = 1;i<trs.length;i++){
var tr = trs.eq(i);
ps.push({
"k" : $.trim(tr.find("td").eq(0).find("span").text()),
"v" : $.trim(tr.find("input").val())
});
}
paramJson.push({
"group" : group,
"params": ps
});
});
paramJson = JSON.stringify(paramJson);
$("#itemeEditForm [name=itemParams]").val(paramJson);
$.post("/rest/item/update",$("#itemeEditForm").serialize(), function(data){
if(data.status == 200){
$.messager.alert('提示','修改商品成功!','info',function(){
$("#itemEditWindow").window('close');
$("#itemList").datagrid("reload");
});
}
});
}
</script>
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>淘淘商城后台管理系统</title>
<link rel="stylesheet" type="text/css" href="js/jquery-easyui-1.4.1/themes/default/easyui.css" />
<link rel="stylesheet" type="text/css" href="js/jquery-easyui-1.4.1/themes/icon.css" />
<link rel="stylesheet" type="text/css" href="css/taotao.css" />
<script type="text/javascript" src="js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery-easyui-1.4.1/jquery.easyui.min.js"></script>
<script type="text/javascript" src="js/jquery-easyui-1.4.1/locale/easyui-lang-zh_CN.js"></script>
<script type="text/javascript" src="js/common.js"></script>
<style type="text/css">
.content {
padding: 10px 10px 10px 10px;
}
</style>
</head>
<body class="easyui-layout">
<div data-options="region:'west',title:'菜单',split:true" style="width:180px;">
<ul id="menu" class="easyui-tree" style="margin-top: 10px;margin-left: 5px;">
<li>
<span>商品管理</span>
<ul>
<li data-options="attributes:{'url':'item-add'}">新增商品</li>
<li data-options="attributes:{'url':'item-list'}">查询商品</li>
<li data-options="attributes:{'url':'item-param-list'}">规格参数</li>
</ul>
</li>
<li>
<span>网站内容管理</span>
<ul>
<li data-options="attributes:{'url':'content-category'}">内容分类管理</li>
<li data-options="attributes:{'url':'content'}">内容管理</li>
</ul>
</li>
<li>
<span>索引库管理</span>
<ul>
<li data-options="attributes:{'url':'import-index'}">导入索引库</li>
</ul>
</li>
</ul>
</div>
<div data-options="region:'center',title:''">
<div id="tabs" class="easyui-tabs">
<div title="首页" style="padding:20px;">
</div>
</div>
</div>
<script type="text/javascript">
$(function(){
$('#menu').tree({
onClick: function(node){
if($('#menu').tree("isLeaf",node.target)){
var tabs = $("#tabs");
var tab = tabs.tabs("getTab",node.text);
if(tab){
tabs.tabs("select",node.text);
}else{
tabs.tabs('add',{
title:node.text,
href: node.attributes.url,
closable:true,
bodyCls:"content"
});
}
}
}
});
});
</script>
</body>
</html>
import-index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<div>
<a class="easyui-linkbutton" onclick="importIndex()">一键导入商品数据到索引库</a>
</div>
<script type="text/javascript">
function importIndex() {
$.post("/index/import",function(data){
if(data.status == 200){
$.messager.alert('提示','导入索引库成功!!!!');
}else{
$.messager.alert('提示','导入索引库失败~~~~~');
}
});
}
</script>
file-upload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html lang="en">
<head>
<!-- Force latest IE rendering engine or ChromeFrame if installed -->
<!--[if IE]>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<![endif]-->
<meta charset="utf-8">
<title>jQuery File Upload Demo</title>
<meta name="description" content="File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap styles -->
<link rel="stylesheet" href="/js/file-upload/bootstrap-3.2.0/css/bootstrap.min.css">
<!-- Generic page styles -->
<link rel="stylesheet" href="/js/file-upload/css/style.css">
<!-- blueimp Gallery styles -->
<link rel="stylesheet" href="/js/file-upload/gallery/css/blueimp-gallery.min.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
<link rel="stylesheet" href="/js/file-upload/css/jquery.fileupload.css">
<link rel="stylesheet" href="/js/file-upload/css/jquery.fileupload-ui.css">
<!-- CSS adjustments for browsers with JavaScript disabled -->
<noscript><link rel="stylesheet" href="/js/file-upload/css/jquery.fileupload-noscript.css"></noscript>
<noscript><link rel="stylesheet" href="/js/file-upload/css/jquery.fileupload-ui-noscript.css"></noscript>
</head>
<body>
<div class="container">
<form id="fileupload" action="/rest/pic/upload" method="POST" enctype="multipart/form-data">
<!-- Redirect browsers with JavaScript disabled to the origin page -->
<noscript><input type="hidden" name="redirect" value="https://blueimp.github.io/jQuery-File-Upload/"></noscript>
<!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
<div class="row fileupload-buttonbar">
<div class="col-lg-7">
<!-- The fileinput-button span is used to style the file input field as button -->
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-plus"></i>
<span>选择文件(多选)</span>
<input type="file" name="files" multiple>
</span>
<button type="submit" class="btn btn-primary start">
<i class="glyphicon glyphicon-upload"></i>
<span>开始上传</span>
</button>
<button type="reset" class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>取消上传</span>
</button>
<button type="button" class="btn btn-danger delete">
<i class="glyphicon glyphicon-trash"></i>
<span>删除</span>
</button>
<input type="checkbox" class="toggle" title="全选">
<!-- The global file processing state -->
<span class="fileupload-process"></span>
</div>
<!-- The global progress state -->
<div class="col-lg-5 fileupload-progress fade">
<!-- The global progress bar -->
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar progress-bar-success" style="width:0%;"></div>
</div>
<!-- The extended global progress state -->
<div class="progress-extended"> </div>
</div>
</div>
<!-- The table listing the files available for upload/download -->
<table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>
</form>
<br>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">说明</h3>
</div>
<div class="panel-body">
<ul>
<li>上传的文件大小限制为:<strong>5 MB</strong>.</li>
<li>只支持的文件格式为:<strong>JPG, GIF, PNG, BMP </strong>.</li>
</ul>
</div>
</div>
</div>
<!-- The blueimp Gallery widget -->
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
<div class="slides"></div>
<h3 class="title"></h3>
<a class="prev">‹</a>
<a class="next">›</a>
<a class="close">×</a>
<a class="play-pause"></a>
<ol class="indicator"></ol>
</div>
<!-- The template to display files available for upload -->
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-upload fade">
<td>
<span class="preview"></span>
</td>
<td>
<p class="name">{%=file.name%}</p>
<strong class="error text-danger"></strong>
</td>
<td>
<p class="size">Processing...</p>
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
</td>
<td>
{% if (!i && !o.options.autoUpload) { %}
<button class="btn btn-primary start" disabled>
<i class="glyphicon glyphicon-upload"></i>
<span>开始</span>
</button>
{% } %}
{% if (!i) { %}
<button class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>取消</span>
</button>
{% } %}
</td>
</tr>
{% } %}
</script>
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-download fade">
<td>
<span class="preview">
{% if (file.url) { %}
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img width="80" height="50" src="{%=file.url%}"></a>
{% } %}
</span>
</td>
<td>
<p class="name">
{% if (file.url) { %}
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.url?'data-gallery':''%}>{%=file.name%}</a>
{% } else { %}
<span>{%=file.name%}</span>
{% } %}
</p>
{% if (file.error) { %}
<div><span class="label label-danger">Error</span> {%=file.error%}</div>
{% } %}
</td>
<td>
<span class="size">{%=o.formatFileSize(file.size)%}</span>
</td>
<td>
{% if (file.deleteUrl) { %}
<button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
<i class="glyphicon glyphicon-trash"></i>
<span>Delete</span>
</button>
<input type="checkbox" name="delete" value="1" class="toggle">
{% } else { %}
<button class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel</span>
</button>
{% } %}
</td>
</tr>
{% } %}
</script>
<script src="/js/file-upload/jquery-1.11.1.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="/js/file-upload/vendor/jquery.ui.widget.js"></script>
<!-- The Templates plugin is included to render the upload/download listings -->
<script src="/js/file-upload/tmpl.min.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
<script src="/js/file-upload/load-image.all.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
<script src="/js/file-upload/canvas-to-blob.min.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
<script src="/js/file-upload/bootstrap-3.2.0/js/bootstrap.min.js"></script>
<!-- blueimp Gallery script -->
<script src="/js/file-upload/gallery/js/jquery.blueimp-gallery.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="/js/file-upload/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
<script src="/js/file-upload/jquery.fileupload.js"></script>
<!-- The File Upload processing plugin -->
<script src="/js/file-upload/jquery.fileupload-process.js"></script>
<!-- The File Upload image preview & resize plugin -->
<script src="/js/file-upload/jquery.fileupload-image.js"></script>
<!-- The File Upload audio preview plugin -->
<script src="/js/file-upload/jquery.fileupload-audio.js"></script>
<!-- The File Upload video preview plugin -->
<script src="/js/file-upload/jquery.fileupload-video.js"></script>
<!-- The File Upload validation plugin -->
<script src="/js/file-upload/jquery.fileupload-validate.js"></script>
<!-- The File Upload user interface plugin -->
<script src="/js/file-upload/jquery.fileupload-ui.js"></script>
<!-- The main application script -->
<script src="/js/file-upload/main.js"></script>
<!-- The XDomainRequest Transport is included for cross-domain file deletion for IE 8 and IE 9 -->
<!--[if (gte IE 8)&(lt IE 10)]>
<script src="/js/file-upload/cors/jquery.xdr-transport.js"></script>
<![endif]-->
</body>
</html>
content-category.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<div>
<ul id="contentCategory" class="easyui-tree">
</ul>
</div>
<div id="contentCategoryMenu" class="easyui-menu" style="width:120px;" data-options="onClick:menuHandler">
<div data-options="iconCls:'icon-add',name:'add'">添加</div>
<div data-options="iconCls:'icon-remove',name:'rename'">重命名</div>
<div class="menu-sep"></div>
<div data-options="iconCls:'icon-remove',name:'delete'">删除</div>
</div>
<script type="text/javascript">
$(function(){
$("#contentCategory").tree({
url : '/content/category/list',
animate: true,
method : "GET",
onContextMenu: function(e,node){
e.preventDefault();
$(this).tree('select',node.target);
$('#contentCategoryMenu').menu('show',{
left: e.pageX,
top: e.pageY
});
},
onAfterEdit : function(node){
var _tree = $(this);
if(node.id == 0){
// 新增节点
$.post("/content/category/create",{parentId:node.parentId,name:node.text},function(data){
if(data.status == 200){
_tree.tree("update",{
target : node.target,
id : data.data.id
});
}else{
$.messager.alert('提示','创建'+node.text+' 分类失败!');
}
});
}else{
$.post("/content/category/update",{id:node.id,name:node.text});
}
}
});
});
function menuHandler(item){
var tree = $("#contentCategory");
var node = tree.tree("getSelected");
if(item.name === "add"){
tree.tree('append', {
parent: (node?node.target:null),
data: [{
text: '新建分类',
id : 0,
parentId : node.id
}]
});
var _node = tree.tree('find',0);
tree.tree("select",_node.target).tree('beginEdit',_node.target);
}else if(item.name === "rename"){
tree.tree('beginEdit',node.target);
}else if(item.name === "delete"){
$.messager.confirm('确认','确定删除名为 '+node.text+' 的分类吗?',function(r){
if(r){
$.post("/content/category/delete/",{id:node.id},function(){
tree.tree("remove",node.target);
});
}
});
}
}
</script>
content.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<div class="easyui-panel" title="Nested Panel" data-options="width:'100%',minHeight:500,noheader:true,border:false" style="padding:10px;">
<div class="easyui-layout" data-options="fit:true">
<div data-options="region:'west',split:false" style="width:250px;padding:5px">
<ul id="contentCategoryTree" class="easyui-tree" data-options="url:'/content/category/list',animate: true,method : 'GET'">
</ul>
</div>
<div data-options="region:'center'" style="padding:5px">
<table class="easyui-datagrid" id="contentList" data-options="toolbar:contentListToolbar,singleSelect:false,collapsible:true,pagination:true,method:'get',pageSize:20,url:'/content/query/list',queryParams:{categoryId:0}">
<thead>
<tr>
<th data-options="field:'id',width:30">ID</th>
<th data-options="field:'title',width:120">内容标题</th>
<th data-options="field:'subTitle',width:100">内容子标题</th>
<th data-options="field:'titleDesc',width:120">内容描述</th>
<th data-options="field:'url',width:60,align:'center',formatter:TAOTAO.formatUrl">内容连接</th>
<th data-options="field:'pic',width:50,align:'center',formatter:TAOTAO.formatUrl">图片</th>
<th data-options="field:'pic2',width:50,align:'center',formatter:TAOTAO.formatUrl">图片2</th>
<th data-options="field:'created',width:130,align:'center',formatter:TAOTAO.formatDateTime">创建日期</th>
<th data-options="field:'updated',width:130,align:'center',formatter:TAOTAO.formatDateTime">更新日期</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
<script type="text/javascript">
$(function(){
var tree = $("#contentCategoryTree");
var datagrid = $("#contentList");
tree.tree({
onClick : function(node){
if(tree.tree("isLeaf",node.target)){
datagrid.datagrid('reload', {
categoryId :node.id
});
}
}
});
});
var contentListToolbar = [{
text:'新增',
iconCls:'icon-add',
handler:function(){
var node = $("#contentCategoryTree").tree("getSelected");
if(!node || !$("#contentCategoryTree").tree("isLeaf",node.target)){
$.messager.alert('提示','新增内容必须选择一个内容分类!');
return ;
}
TT.createWindow({
url : "/content-add"
});
}
},{
text:'编辑',
iconCls:'icon-edit',
handler:function(){
var ids = TT.getSelectionsIds("#contentList");
if(ids.length == 0){
$.messager.alert('提示','必须选择一个内容才能编辑!');
return ;
}
if(ids.indexOf(',') > 0){
$.messager.alert('提示','只能选择一个内容!');
return ;
}
TT.createWindow({
url : "/content-edit",
onLoad : function(){
var data = $("#contentList").datagrid("getSelections")[0];
$("#contentEditForm").form("load",data);
// 实现图片
if(data.pic){
$("#contentEditForm [name=pic]").after("<a href='"+data.pic+"' target='_blank'><img src='"+data.pic+"' width='80' height='50'/></a>");
}
if(data.pic2){
$("#contentEditForm [name=pic2]").after("<a href='"+data.pic2+"' target='_blank'><img src='"+data.pic2+"' width='80' height='50'/></a>");
}
contentEditEditor.html(data.content);
}
});
}
},{
text:'删除',
iconCls:'icon-cancel',
handler:function(){
var ids = TT.getSelectionsIds("#contentList");
if(ids.length == 0){
$.messager.alert('提示','未选中商品!');
return ;
}
$.messager.confirm('确认','确定删除ID为 '+ids+' 的内容吗?',function(r){
if (r){
var params = {"ids":ids};
$.post("/content/delete",params, function(data){
if(data.status == 200){
$.messager.alert('提示','删除内容成功!',undefined,function(){
$("#contentList").datagrid("reload");
});
}
});
}
});
}
}];
</script>
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- 加载属性文件 -->
<context:property-placeholder location="classpath:resource/resource.properties"/>
<!-- 配置注解驱动 -->
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- 配置包扫描器,扫描@Controller注解的类 -->
<context:component-scan base-package="com.taotao.controller"/>
<!-- 配置资源映射 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<!-- 多媒体解析器 -->
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设定默认编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设定文件上传的最大值5MB,5*1024*1024 -->
<property name="maxUploadSize" value="5242880"></property>
</bean>
<!-- 引用dubbo服务 -->
<dubbo:application name="taotao-manager-web"/>
<dubbo:registry protocol="zookeeper" address="192.168.25.167:2181"/>
<dubbo:reference interface="com.taotao.service.ItemService" id="itemService" />
<dubbo:reference interface="com.taotao.service.ItemCatService" id="itemCatService" />
<dubbo:reference interface="com.taotao.content.service.ContentCategoryService" id="contentCategoryService" />
<dubbo:reference interface="com.taotao.content.service.ContentService" id="contentService" />
<dubbo:reference interface="com.taotao.search.service.SearchItemService" id="searchItemService" />
</beans>
resource.properties
#\u56fe\u7247\u670d\u52a1\u7684url
IMAGE_SERVER_URL=http://192.168.25.133/
client.conf
tracker_server=192.168.25.133:22122
FastDFSClient.java
package com.taotao.utils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
public class FastDFSClient {
private TrackerClient trackerClient = null;
private TrackerServer trackerServer = null;
private StorageServer storageServer = null;
private StorageClient1 storageClient = null;
public FastDFSClient(String conf) throws Exception {
if (conf.contains("classpath:")) {
conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());
}
ClientGlobal.init(conf);
trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
storageServer = null;
storageClient = new StorageClient1(trackerServer, storageServer);
}
/**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
* @param fileName 文件全路径
* @param extName 文件扩展名,不包含(.)
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(String fileName, String extName, NameValuePair[] metas) throws Exception {
String result = storageClient.upload_file1(fileName, extName, metas);
return result;
}
public String uploadFile(String fileName) throws Exception {
return uploadFile(fileName, null, null);
}
public String uploadFile(String fileName, String extName) throws Exception {
return uploadFile(fileName, extName, null);
}
/**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
* @param fileContent 文件的内容,字节数组
* @param extName 文件扩展名
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) throws Exception {
String result = storageClient.upload_file1(fileContent, extName, metas);
return result;
}
public String uploadFile(byte[] fileContent) throws Exception {
return uploadFile(fileContent, null, null);
}
public String uploadFile(byte[] fileContent, String extName) throws Exception {
return uploadFile(fileContent, extName, null);
}
}
PictureController.java
package com.taotao.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.taotao.common.utils.JsonUtils;
import com.taotao.utils.FastDFSClient;
/**
* 图片上传controller
* <p>Title: PictureController</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
@Controller
public class PictureController {
@Value("${IMAGE_SERVER_URL}")
private String IMAGE_SERVER_URL;
@RequestMapping("/pic/upload")
@ResponseBody
public String picUpload(MultipartFile uploadFile) {
try {
//接收上传的文件
//取扩展名
String originalFilename = uploadFile.getOriginalFilename();
String extName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
//上传到图片服务器
FastDFSClient fastDFSClient = new FastDFSClient("classpath:resource/client.conf");
String url = fastDFSClient.uploadFile(uploadFile.getBytes(), extName);
url = IMAGE_SERVER_URL + url;
//响应上传图片的url
Map result = new HashMap<>();
result.put("error", 0);
result.put("url", url);
return JsonUtils.objectToJson(result);
} catch (Exception e) {
e.printStackTrace();
Map result = new HashMap<>();
result.put("error", 1);
result.put("message", "图片上传失败");
return JsonUtils.objectToJson(result);
}
}
}
PageController.java
package com.taotao.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 页面展示Controller
* <p>Title: PageController</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
@Controller
public class PageController {
@RequestMapping("/")
public String showIndex() {
return "index";
}
@RequestMapping("/{page}")
public String showPage(@PathVariable String page) {
return page;
}
}
ItemController.java
package com.taotao.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.common.pojo.EasyUIDataGridResult;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.pojo.TbItem;
import com.taotao.service.ItemService;
/**
* 商品管理Controller
* <p>Title: ItemController</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
@Controller
public class ItemController {
@Autowired
private ItemService itemService;
@RequestMapping("/item/{itemId}")
@ResponseBody
public TbItem getItemById(@PathVariable Long itemId) {
TbItem tbItem = itemService.getItemById(itemId);
return tbItem;
}
@RequestMapping("/item/list")
@ResponseBody
public EasyUIDataGridResult getItemList(Integer page, Integer rows) {
EasyUIDataGridResult result = itemService.getItemList(page, rows);
return result;
}
@RequestMapping(value="/item/save", method=RequestMethod.POST)
@ResponseBody
public TaotaoResult addItem(TbItem item, String desc) {
TaotaoResult result = itemService.addItem(item, desc);
return result;
}
}
ItemCatController.java
package com.taotao.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.common.pojo.EasyUITreeNode;
import com.taotao.service.ItemCatService;
/**
* 商品分类管理Controller
* <p>Title: ItemCatController</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
@Controller
public class ItemCatController {
@Autowired
private ItemCatService itemCatService;
@RequestMapping("/item/cat/list")
@ResponseBody
public List<EasyUITreeNode> getItemCatList(@RequestParam(name="id", defaultValue="0")Long parentId) {
List<EasyUITreeNode> list = itemCatService.getItemCatList(parentId);
return list;
}
}
package com.taotao.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.search.service.SearchItemService;
/**
* 索引库维护Controller
* <p>Title: IndexManagerController</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
@Controller
public class IndexManagerController {
@Autowired
private SearchItemService searchItemService;
@RequestMapping("/index/import")
@ResponseBody
public TaotaoResult importIndex() {
TaotaoResult taotaoResult = searchItemService.importItemsToIndex();
return taotaoResult;
}
}
package com.taotao.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.content.service.ContentService;
import com.taotao.pojo.TbContent;
/**
* 内容管理Controller
* <p>Title: ContentController</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
@Controller
public class ContentController {
@Autowired
private ContentService contentService;
@RequestMapping("/content/save")
@ResponseBody
public TaotaoResult addContent(TbContent content) {
TaotaoResult result = contentService.addContent(content);
return result;
}
}
package com.taotao.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.common.pojo.EasyUITreeNode;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.content.service.ContentCategoryService;
/**
* 内容分类管理Controller
* <p>Title: ContentCategoryController</p>
* <p>Description: </p>
* <p>Company: www.itcast.cn</p>
* @version 1.0
*/
@Controller
public class ContentCategoryController {
@Autowired
private ContentCategoryService contentCategoryService;
@RequestMapping("/content/category/list")
@ResponseBody
public List<EasyUITreeNode> getContentCategoryList(
@RequestParam(value="id", defaultValue="0")Long parentId) {
List<EasyUITreeNode> list = contentCategoryService.getContentCategoryList(parentId);
return list;
}
@RequestMapping("/content/category/create")
@ResponseBody
public TaotaoResult addContentCategory(Long parentId, String name) {
TaotaoResult result = contentCategoryService.addContentCategory(parentId, name);
return result;
}
}