YONGFEIUALL

izheyi.com


  • Home

  • Archives

  • Categories

  • Tags

  • About

  • Search

Java项目实战 - solr安装与配置

Posted on 2018-07-22 | In Java |

Solr是一个全文检索服务器,只需要进行配置就可以实现全文检索服务。

安装

  1. 前提,有JDK和Tomcat。
  2. 下载solr的安装包,解压,并把dist下的war包部署到Tomcat下。
  3. 解压war包。启动tomcat自动解压。
  4. 把solr/example/lib/ext目录下所有的jar包复制Tomcat下/webapps/solr/WEB-INF/lib/。
  5. 创建solrhome,把example/sor复制到/opt/solrhome。
  6. 配置solrhome,在/apache-tomcat-8.0.28/webapps/solr/WEB-INF/web.xml。
  7. 启动Tomcat。

中文分析器IK-Analyzer

Solr中默认是没有中文分析器的,需要手工配置,配置一个FieldType,在FieldType中指定使用的中文分析器。

  1. 下载包。
  2. 把中文分析器的jar复制到Tomcat下/webapps/solr/WEB-INF/lib/。
  3. 把IK Analyzer需要的扩展词典及停用词词典、配置文件复制到Tomcat下/webapps/solr/WEB-INF/classes。
  4. 在solrhome/collection1/conf/schema.xml中配置FileType。

配置业务域

就是配置要搜索的字段,和后续用到的字段。
业务系统Fileds:

1
2
3
4
5
6
7
8
9
10
11
12
<field name="item_title" type="text_ik" indexed="true" stored="true"/>
<field name="item_sell_point" type="text_ik" indexed="true" stored="true"/>
<field name="item_price" type="long" indexed="true" stored="true"/>
<field name="item_image" type="string" indexed="false" stored="true" />
<field name="item_category_name" type="string" indexed="true" stored="true" />
<field name="item_desc" type="text_ik" indexed="true" stored="false" />

<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
<copyField source="item_title" dest="item_keywords"/>
<copyField source="item_sell_point" dest="item_keywords"/>
<copyField source="item_category_name" dest="item_keywords"/>
<copyField source="item_desc" dest="item_keywords"/>

Java项目实战 - Redis缓存同步

Posted on 2018-07-21 | In Java |

缓存有个问题就是如果数据库表中的数据做了修改,缓存是需要同步的,否则查询的还是老数据,所有涉及增、删、改的操作都需要同步缓存。

我们创建一个rest服务供manager-service层调用。

Redis Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service
public class RedisServiceImpl implements RedisService {

@Value("${CONTENT_KEY}")
private String CONTENT_KEY;

@Autowired
private RedisUtils redisUtils;

@Override
public TaotaoResult syncContent(long contentCategoryId) {
try {
redisUtils.hdel(CONTENT_KEY, contentCategoryId + "");
} catch (Exception e) {
// TODO: handle exception
}
return TaotaoResult.ok();
}
}

Redis Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller
@RequestMapping("/cache")
public class RedisController {

@Autowired
private RedisService redisService;

@RequestMapping("/content/{contentCategoryId}")
@ResponseBody
public TaotaoResult syncContent(@PathVariable long contentCategoryId) {
TaotaoResult result = redisService.syncContent(contentCategoryId);

return result;
}
}

Content Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public TaotaoResult createContent(TbContent tbContent) {
tbContent.setCreated(new Date());
tbContent.setUpdated(new Date());

contentMapper.insert(tbContent);

//添加缓存同步
try {
HttpClientUtil.doGet(REST_BASE_URL + REST_CONTENT_SYNC_URL + tbContent.getCategoryId());
} catch (Exception e) {
e.printStackTrace();
}

return TaotaoResult.ok();
}

Verify

在后台添加一个Content,删除缓存。

Java项目实战 - Redis集成Spring

Posted on 2018-07-21 | In Java |

一般只会在生产环境使用集群,而开发环境使用Redis单机版,所以我们在整合项目的时候,单机版和集群版都要有。

Spring整合Redis

创建一个接口,再编写单机版和集群版的实现类,使用spring进行管理,在部署时,使用哪种Redis,就切换那种实现类。

实现

Interface:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.izheyi.rest.redis;

public interface RedisUtils {
String set(String key, String value);
String get(String key);
Boolean exists(String key);
Long expire(String key, int seconds);
Long ttl(String key);
Long incr(String key);
Long hset(String key, String field, String value);
String hget(String key, String field);
Long hdel(String key, String... field);
}

单机版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public class RedisPool implements RedisUtils {

@Autowired
private JedisPool jedisPool;

@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String result = jedis.set(key, value);
jedis.close();
return result;
}

@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
String result = jedis.get(key);
jedis.close();
return result;
}

@Override
public Boolean exists(String key) {
Jedis jedis = jedisPool.getResource();
Boolean result = jedis.exists(key);
jedis.close();
return result;
}

@Override
public Long expire(String key, int seconds) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, seconds);
jedis.close();
return result;
}

@Override
public Long ttl(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
}

@Override
public Long incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}

@Override
public Long hset(String key, String field, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(key, field, value);
jedis.close();
return result;
}

@Override
public String hget(String key, String field) {
Jedis jedis = jedisPool.getResource();
String result = jedis.hget(key, field);
jedis.close();
return result;
}

@Override
public Long hdel(String key, String... field) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(key, field);
jedis.close();
return result;
}

}

集群版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class RedisCluster implements RedisUtils {

@Autowired
private JedisCluster jedisCluster;

@Override
public String set(String key, String value) {
return jedisCluster.set(key, value);
}

@Override
public String get(String key) {
return jedisCluster.get(key);
}

@Override
public Boolean exists(String key) {
return jedisCluster.exists(key);
}

@Override
public Long expire(String key, int seconds) {
return jedisCluster.expire(key, seconds);
}

@Override
public Long ttl(String key) {
return jedisCluster.ttl(key);
}

@Override
public Long incr(String key) {
return jedisCluster.incr(key);
}

@Override
public Long hset(String key, String field, String value) {
return jedisCluster.hset(key, field, value);
}

@Override
public String hget(String key, String field) {
return jedisCluster.hget(key, field);
}

@Override
public Long hdel(String key, String... field) {
return jedisCluster.hdel(key, field);
}
}

applicationContext-redis.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!-- 两种方案:使用jedis连接池(单机版)和jedis集群 -->
<!-- 一般生产环境使用集群,开发环境使用单机版 -->
<!-- 使用哪种,可以将另一种注释掉 -->

<!-- 单机版 -->
<!-- 配置jedis连接池 -->
<bean class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="${redis.host}" />
<constructor-arg name="port" value="${redis.port}" />
</bean>

<!-- 集群版 -->
<!-- 配置jedis集群 -->
<bean class="redis.clients.jedis.JedisCluster">
<constructor-arg name="nodes">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host1}" />
<constructor-arg name="port" value="${cluster.port1}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host2}" />
<constructor-arg name="port" value="${cluster.port2}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host3}" />
<constructor-arg name="port" value="${cluster.port3}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host4}" />
<constructor-arg name="port" value="${cluster.port4}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host5}" />
<constructor-arg name="port" value="${cluster.port5}" />
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="${cluster.host6}" />
<constructor-arg name="port" value="${cluster.port6}" />
</bean>
</set>
</constructor-arg>
</bean>

添加到业务中

缓存的添加不能影响正常的业务逻辑。

以首页大广告位的展示为例。在请求的时候如果有缓存,就直接响应;如果没有,就从DB中读取,并写入到缓存中,再响应。
对获得大广告位的Service进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public List<TbContent> getContentList(long contentCategoryId) {
// 查询数据库之前,先查询缓存
try {
String json = redisUtils.hget(CONTENT_KEY, contentCategoryId + "");
// 判断是否命中缓存
if (StringUtils.isNotBlank(json)) {
// 把这个json转换成List集合
List<TbContent> list = JsonUtils.jsonToList(json, TbContent.class);
return list;
}
} catch (Exception e) {
e.printStackTrace();
}

TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(contentCategoryId);

List<TbContent> result = contentMapper.selectByExample(example);

// 添加缓存,并且不能影响正常业务逻辑
try {
redisUtils.hset(CONTENT_KEY, contentCategoryId + "", JsonUtils.objectToJson(result));
} catch (Exception e) {
e.printStackTrace();
}
return result;
}

验证

刷新首页,检查redis缓存。

1
2
3
4
5
127.0.0.1:6379> hget CONTENT_KEY 89
(nil)
127.0.0.1:6379> hget CONTENT_KEY 89
"[{\"id\":33,\"categoryId\":89,\"title\":\"ad1\",\"subTitle\":\"ad1\",\"titleDesc\":\"ad1\",\"url\":\"http://google.com\",\"pic\":\"http://192.168.220.133/images/2018/07/18/c7ae33f0-1e56-451c-94b3-a7cc5dbd5101.jpg\",\"pic2\":\"http://192.168.220.133/images/2018/07/18/f7622208-d7df-4a95-b279-69e48c148fdf.jpg\",\"created\":1531905943000,\"updated\":1531905943000,\"content\":null},{\"id\":34,\"categoryId\":89,\"title\":\"ad2\",\"subTitle\":\"ad2\",\"titleDesc\":\"ad2\",\"url\":\"#\",\"pic\":\"http://192.168.220.133/images/2018/07/18/b83eae10-105e-4fa4-8b46-26f16114c11b.jpg\",\"pic2\":\"http://192.168.220.133/images/2018/07/18/7dec8ede-5fae-4e80-90cc-15a6a7781355.jpg\",\"created\":1531905966000,\"updated\":1531905966000,\"content\":null},{\"id\":35,\"categoryId\":89,\"title\":\"ad3\",\"subTitle\":\"ad3\",\"titleDesc\":\"ad3\",\"url\":\"ad3\",\"pic\":\"http://192.168.220.133/images/2018/07/18/7adf566c-2967-4e99-9265-283244d3379d.jpg\",\"pic2\":\"http://192.168.220.133/images/2018/07/18/2381bf63-2b89-40ad-858c-498ea01e5abf.jpg\",\"created\":1531905995000,\"updated\":1531905995000,\"content\":null}]"
127.0.0.1:6379>

Java项目实战 - Redis安装和集群搭建

Posted on 2018-07-21 | In Java |

Redis

Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下:

  • 字符串类型
  • 散列类型
  • 列表类型
  • 集合类型
  • 有序集合类型

详细内容,参考:Redis

安装

安装还是很简单的,如下:

1
2
3
4
$ wget http://download.redis.io/releases/redis-4.0.10.tar.gz
$ tar xzf redis-4.0.10.tar.gz
$ cd redis-4.0.10
$ make

运行

  1. 直接启动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [root@Automation redis-4.0.10]# src/redis-server 
    9833:C 13 Jun 23:58:18.056 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    9833:C 13 Jun 23:58:18.056 # Redis version=4.0.10, bits=64, commit=00000000, modified=0, pid=9833, just started
    9833:C 13 Jun 23:58:18.056 # Warning: no config file specified, using the default config. In order to specify a config file use src/redis-server /path/to/redis.conf
    9833:M 13 Jun 23:58:18.058 * Increased maximum number of open files to 10032 (it was originally set to 1024).
    _._
    _.-``__ ''-._
    _.-`` `. `_. ''-._ Redis 4.0.10 (00000000/0) 64 bit
    .-`` .-```. ```\/ _.,_ ''-._
    ( ' , .-` | `, ) Running in standalone mode
    |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
    | `-._ `._ / _.-' | PID: 9833
    `-._ `-._ `-./ _.-' _.-'

    |`-._`-._ `-.__.-' _.-'_.-'|
    | `-._`-._ _.-'_.-' | http://redis.io
    `-._ `-._`-.__.-'_.-' _.-'
    |`-._`-._ `-.__.-' _.-'_.-'|

    | `-._`-._ _.-'_.-' |
    `-._ `-._`-.__.-'_.-' _.-'
    `-._ `-.__.-' _.-'
    `-._ _.-'
    `-.__.-'

  2. 指定配置文件启动
    把redis的解压缩目录的redis.conf文件复制一份到/usr/local/redis/bin目录下

    1
    2
    3
    4
    [root@Automation redis-4.0.10]# src/redis-server redis.conf 
    12033:C 14 Jun 00:15:48.382 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    12033:C 14 Jun 00:15:48.383 # Redis version=4.0.10, bits=64, commit=00000000, modified=0, pid=12033, just started
    12033:C 14 Jun 00:15:48.383 # Configuration loaded
  3. 验证

    1
    2
    3
    4
    5
    6
    [root@Automation redis-4.0.10]# src/redis-cli 
    127.0.0.1:6379> set a 10
    OK
    127.0.0.1:6379> get a
    "10"
    127.0.0.1:6379>
  4. 关闭

    1
    [root@Automation redis-4.0.10]# src/redis-cli shutdown

集群搭建

需要安装以下环境

  • ruby的环境:yum install ruby
  • rubygems组件:yum install rubygems
  • redis和ruby的接口:gem install redis

在同一台机器上搭建环境

  1. 在/usr/local/下创建文件夹redis-cluster
  2. 为每个实例创建一个文件夹,共6个

    1
    2
    [root@Automation redis-cluster]# ls
    7001 7002 7003 7004 7005 7006
  3. 把redis安装目录bin Copy到6个文件夹

  4. 修改每个实例
    1. Port 7001 - 7006
    2. 屏蔽限制本地访问,在bind 127.0.0.1之前加#
    3. protected-mode后的yes改为no
    4. daemonize后的no改为yes
    5. 去掉cluster-enabled前面的#
    6. 去掉cluster-node-timeout前面的#
  5. 启动6个实例 - 可以建个脚本一并启动
  6. 验证启动
    redis-cluster]# ps -ef | grep redis
    1
    root     24891     1  0 00:05 ?        00:00:00 ./redis-server 127.0.0.1:7001 [cluster]
    root     24896     1  0 00:05 ?        00:00:00 ./redis-server 127.0.0.1:7002 [cluster]
    root     24901     1  0 00:05 ?        00:00:00 ./redis-server 127.0.0.1:7003 [cluster]
    root     24906     1  0 00:05 ?        00:00:00 ./redis-server 127.0.0.1:7004 [cluster]
    root     24911     1  0 00:05 ?        00:00:00 ./redis-server 127.0.0.1:7005 [cluster]
    root     24913     1  0 00:05 ?        00:00:00 ./redis-server 127.0.0.1:7006 [cluster]
    root     24921 23221  0 00:05 pts/2    00:00:00 grep redis

创建集群

  1. 创建
    把这个脚本(redis-trib.rb)从解压目录下复制到/usr/local/redis-cluster。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    [root@Automation redis-cluster]# ./redis-trib.rb create --replicas 1 10.24.33.147:7001 10.24.33.147:7002 10.24.33.147:7003 10.24.33.147:7004 10.24.33.147:7005  10.24.33.147:7006
    >>> Creating cluster
    >>> Performing hash slots allocation on 6 nodes...
    Using 3 masters:
    10.24.33.147:7001
    10.24.33.147:7002
    10.24.33.147:7003
    Adding replica 10.24.33.147:7005 to 10.24.33.147:7001
    Adding replica 10.24.33.147:7006 to 10.24.33.147:7002
    Adding replica 10.24.33.147:7004 to 10.24.33.147:7003
    >>> Trying to optimize slaves allocation for anti-affinity
    [WARNING] Some slaves are in the same host as their master
    M: 6d9cab72763d1a1fe85be04b6448998b88ea18a2 10.24.33.147:7001
    slots:0-5460 (5461 slots) master
    M: c7693a9c9e1189196481f65153ed41ca9a6fe449 10.24.33.147:7002
    slots:5461-10922 (5462 slots) master
    M: e3c3977d52165dcb589f59d16a713888abdc0c56 10.24.33.147:7003
    slots:10923-16383 (5461 slots) master
    S: 089b61bc451920a7a0cba996a4a430b8a8805c03 10.24.33.147:7004
    replicates e3c3977d52165dcb589f59d16a713888abdc0c56
    S: f3e9541424af4fcad212456d2f5ae5b6a3563525 10.24.33.147:7005
    replicates 6d9cab72763d1a1fe85be04b6448998b88ea18a2
    S: 0c16f9babaa8def8b721bcd82e43d9258f3f68d9 10.24.33.147:7006
    replicates c7693a9c9e1189196481f65153ed41ca9a6fe449
    Can I set the above configuration? (type 'yes' to accept): yes
    >>> Nodes configuration updated
    >>> Assign a different config epoch to each node
    >>> Sending CLUSTER MEET messages to join the cluster
    Waiting for the cluster to join.....
    >>> Performing Cluster Check (using node 10.24.33.147:7001)
    M: 6d9cab72763d1a1fe85be04b6448998b88ea18a2 10.24.33.147:7001
    slots:0-5460 (5461 slots) master
    1 additional replica(s)
    S: f3e9541424af4fcad212456d2f5ae5b6a3563525 10.24.33.147:7005
    slots: (0 slots) slave
    replicates 6d9cab72763d1a1fe85be04b6448998b88ea18a2
    M: e3c3977d52165dcb589f59d16a713888abdc0c56 10.24.33.147:7003
    slots:10923-16383 (5461 slots) master
    1 additional replica(s)
    S: 0c16f9babaa8def8b721bcd82e43d9258f3f68d9 10.24.33.147:7006
    slots: (0 slots) slave
    replicates c7693a9c9e1189196481f65153ed41ca9a6fe449
    S: 089b61bc451920a7a0cba996a4a430b8a8805c03 10.24.33.147:7004
    slots: (0 slots) slave
    replicates e3c3977d52165dcb589f59d16a713888abdc0c56
    M: c7693a9c9e1189196481f65153ed41ca9a6fe449 10.24.33.147:7002
    slots:5461-10922 (5462 slots) master
    1 additional replica(s)
    [OK] All nodes agree about slots configuration.
    >>> Check for open slots...
    >>> Check slots coverage...
    [OK] All 16384 slots covered.
  2. 验证

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@Automation 7001]# redis-cli -h 10.24.33.147 -p 7001 -c
    10.24.33.147:7001> CLUSTER NODES
    f3e9541424af4fcad212456d2f5ae5b6a3563525 10.24.33.147:7005@17005 slave 6d9cab72763d1a1fe85be04b6448998b88ea18a2 0 1528994341234 5 connected
    e3c3977d52165dcb589f59d16a713888abdc0c56 10.24.33.147:7003@17003 master - 0 1528994340000 3 connected 10923-16383
    0c16f9babaa8def8b721bcd82e43d9258f3f68d9 10.24.33.147:7006@17006 slave c7693a9c9e1189196481f65153ed41ca9a6fe449 0 1528994339000 6 connected
    6d9cab72763d1a1fe85be04b6448998b88ea18a2 10.24.33.147:7001@17001 myself,master - 0 1528994338000 1 connected 0-5460
    089b61bc451920a7a0cba996a4a430b8a8805c03 10.24.33.147:7004@17004 slave e3c3977d52165dcb589f59d16a713888abdc0c56 0 1528994339221 4 connected
    c7693a9c9e1189196481f65153ed41ca9a6fe449 10.24.33.147:7002@17002 master - 0 1528994340228 2 connected 5461-10922
    10.24.33.147:7001> set a 100
    -> Redirected to slot [15495] located at 10.24.33.147:7003
    OK
    10.24.33.147:7003> get a
    "100"

Java项目实战 - 通过httpclient实现前后端调用

Posted on 2018-07-20 | In Java |

实现效果:中间大广告显示

实现前端系统获取后端系统提供的接口。zheyi-portal调用zheyi-rest调用zheyi-manager。

Rest层

在zheyi-rest工程下创建。
Service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Service
public class ContentServiceImpl implements ContentService {

@Autowired
private TbContentMapper contentMapper;

@Override
public List<TbContent> getContentList(long contentCategoryId) {
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(contentCategoryId);

List<TbContent> result = contentMapper.selectByExample(example);
return result;
}

}

Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Controller
@RequestMapping("/content")
public class ContentServiceController {

@Autowired
private ContentService contentService;

@RequestMapping("/list/{contentCategoryId}")
@ResponseBody
public TaotaoResult getContentList(@PathVariable long contentCategoryId){
List<TbContent> result = contentService.getContentList(contentCategoryId);

return TaotaoResult.ok(result);
}

}

httpclient

HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。
官网: httpclient

Frontend层

在zheyi-portal,需要使用httpclient调用taotao-rest的服务。
Service:
返回一个json字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Service
public class ContentServiceImpl implements ContentService {

@Value("${REST_BASE_URL}")
private String REST_BASE_URL;
@Value("${REST_INDEX_AD_URL}")
private String REST_INDEX_AD_URL;


@Override
public String getContentList() {
String result = HttpClientUtil.doGet(REST_BASE_URL + REST_INDEX_AD_URL);
TaotaoResult taotaoResult = TaotaoResult.formatToList(result, TbContent.class);
//取内容列表
List<TbContent> list = (List<TbContent>) taotaoResult.getData();
List<Map> resultList = new ArrayList<>();
//创建一个jsp页码要求的pojo列表
for (TbContent tbContent : list) {
Map map = new HashMap<>();
map.put("src", tbContent.getPic());
map.put("height", 240);
map.put("width", 670);
map.put("srcB", tbContent.getPic2());
map.put("widthB", 550);
map.put("heightB", 240);
map.put("href", tbContent.getUrl());
map.put("alt", tbContent.getSubTitle());
resultList.add(map);
}
return JsonUtils.objectToJson(resultList);

}

}

Controller:
返回一个逻辑视图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
public class HomeConrtoller {

@Autowired
private ContentService contentService;

@RequestMapping("/index")
public String home(Model model){
String adJson = contentService.getContentList();
model.addAttribute("ad1", adJson);

return "index";
}
}

Java项目实战 - 前台工程搭建

Posted on 2018-07-19 | In Java |

把Service和Frontend分离,创建两个独立的war工程:

zheyi-rest

要配置的项:

  • Mybatis
  • Spring
  • Springmvc
  • web.xml

运行:

zheyi-portal

要配置的项:

  • Spring
  • Springmvc
  • Jstl、jQuery
  • web.xml

添加前端相关静态资源。

运行:

Java项目实战 - CMS实现

Posted on 2018-07-18 | In Java |

最终实现效果:

内容分类管理

实现内容分类列表的展示和内容的添加功能。
Service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@Service
public class ContentCategoryServiceImpl implements ContentCategoryService {

@Autowired
private TbContentCategoryMapper contentCategoryMapper;

@Override
public List<EasyUiTreeNode> getContentCategoryList(long parentId) {

TbContentCategoryExample example = new TbContentCategoryExample();
Criteria criteria = example.createCriteria();
criteria.andParentIdEqualTo(parentId);

List<TbContentCategory> list = contentCategoryMapper.selectByExample(example);


List<EasyUiTreeNode> resultList = new ArrayList<>();
for (TbContentCategory tbContentCategory : list) {
EasyUiTreeNode node = new EasyUiTreeNode();
node.setId(tbContentCategory.getId());
node.setText(tbContentCategory.getName());
node.setState(tbContentCategory.getIsParent()?"closed":"open");
resultList.add(node);
}
return resultList;
}

@Override
public TaotaoResult createContentCategory(long parentId, String name) {
TbContentCategory contentCategory = new TbContentCategory();

contentCategory.setParentId(parentId);
contentCategory.setIsParent(false);
contentCategory.setName(name);
contentCategory.setStatus(1);
contentCategory.setSortOrder(1);
contentCategory.setCreated(new Date());
contentCategory.setUpdated(new Date());

contentCategoryMapper.insert(contentCategory);

TbContentCategory parentCategory = contentCategoryMapper.selectByPrimaryKey(parentId);
if(!parentCategory.getIsParent()){
parentCategory.setIsParent(true);
contentCategoryMapper.updateByPrimaryKey(parentCategory);
}

return TaotaoResult.ok(contentCategory);
}

}

Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Controller
@RequestMapping("/content/category")
public class ContentCategoryController {

@Autowired
private ContentCategoryService contentCategoryService;

@RequestMapping("/list")
@ResponseBody
public List<EasyUiTreeNode> getContentCategoryList(@RequestParam(value="id", defaultValue="0")long parentId) {
List<EasyUiTreeNode> result = contentCategoryService.getContentCategoryList(parentId);

return result;
}

@RequestMapping("/create")
@ResponseBody
public TaotaoResult createContentCategory(long parentId, String name){
TaotaoResult result = contentCategoryService.createContentCategory(parentId, name);

return result;
}


}

内容管理

实现内容列表的展示和内容的添加功能。
Service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Service
public class ContentServiceImpl implements ContentService {

@Autowired
private TbContentMapper contentMapper;

@Override
public EasyUiDataGridResult getContentList(long categoryId, int page, int rows) {
TbContentExample example = new TbContentExample();

PageHelper.startPage(page, rows);
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(categoryId);

List<TbContent> list = contentMapper.selectByExample(example);

EasyUiDataGridResult result = new EasyUiDataGridResult();
result.setRows(list);

PageInfo<TbContent> pageInfo = new PageInfo<>(list);
result.setTotal(pageInfo.getTotal());

return result;
}

@Override
public TaotaoResult createContent(TbContent tbContent) {
tbContent.setCreated(new Date());
tbContent.setUpdated(new Date());

contentMapper.insert(tbContent);

return TaotaoResult.ok();
}

}

Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Controller
@RequestMapping("/content")
public class ContentController {

@Autowired
private ContentService contentService;

@RequestMapping("/query/list")
@ResponseBody
public EasyUiDataGridResult getContentList(long categoryId, int page, int rows){
EasyUiDataGridResult result = contentService.getContentList(categoryId, page, rows);
return result;
}

@RequestMapping("/save")
@ResponseBody
public TaotaoResult createContent(TbContent tbContent){
TaotaoResult result = contentService.createContent(tbContent);
return result;
}

}

问题

逆向工程自动生成的insert方法不会自动帮我们给主键的值赋值,需要添加主键返回,在TbContentCategoryMapper.xml文件中做如下修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<insert id="insert" parameterType="com.izheyi.pojo.TbContentCategory" >
<selectKey keyProperty="id" resultType="long" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
insert into tb_content_category (id, parent_id, name,
status, sort_order, is_parent,
created, updated)
values (#{id,jdbcType=BIGINT}, #{parentId,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR},
#{status,jdbcType=INTEGER}, #{sortOrder,jdbcType=INTEGER}, #{isParent,jdbcType=BIT},
#{created,jdbcType=TIMESTAMP}, #{updated,jdbcType=TIMESTAMP})
</insert>
<insert id="insertSelective" parameterType="com.izheyi.pojo.TbContentCategory" >
<selectKey keyProperty="id" resultType="long" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
insert into tb_content_category
<trim prefix="(" suffix=")" suffixOverrides="," >

Java项目实战 - 实现商品添加

Posted on 2018-07-17 | In Java |

商品的添加不只添加基本的商品信息,还要添加商品描述信息。

Dao

逆向工程已经实现了Mapper,不需要再做修改

Service

在ItemService中实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Override
public TaotaoResult createItem(TbItem item, String desc) {
// 补全字段
long itemId = IDUtils.genItemId();
item.setId(itemId); //id
item.setStatus((byte) 1); //商品状态,1-正常,2-下架,3-删除
item.setCreated(new Date());
item.setUpdated(new Date());

//Add Item
itemMapper.insert(item);

//Insert Desc
TaotaoResult result = insertItemDesc(itemId, desc);

return TaotaoResult.ok();
}

private TaotaoResult insertItemDesc(Long itemId, String desc){
TbItemDesc itemDesc = new TbItemDesc();
itemDesc.setItemId(itemId);
itemDesc.setItemDesc(desc);
itemDesc.setCreated(new Date());
itemDesc.setUpdated(new Date());
itemDescMapper.insert(itemDesc);

return TaotaoResult.ok();

}

Controller

在ItemServiceController中实现。

1
2
3
4
5
6
@RequestMapping(value = "/save", method = RequestMethod.POST)
@ResponseBody
public TaotaoResult createItem(TbItem item, String desc){
TaotaoResult result = itemService.createItem(item, desc);
return result;
}

DB结果验证

商品:

1
2
3
4
5
6
7
mysql> SELECT * FROM `tb_item` where title='商务投资';

+-----------------+----------+------------+-------+------+---------+-----------------------------------------------------------------------------------+-----+--------+---------------------+---------------------+
| id | title | sell_point | price | num | barcode | image | cid | status | created | updated |
+-----------------+----------+------------+-------+------+---------+-----------------------------------------------------------------------------------+-----+--------+---------------------+---------------------+
| 153156317952887 | 商务投资 | 商务投资 | 33300 | 4444 | 1241324 | http://192.168.220.133/images/2018/07/14/f93d15e9-2153-4d81-af0b-32fe26d63f01.png | 13 | 1 | 2018-07-14 18:13:00 | 2018-07-14 18:13:00 |
+-----------------+----------+------------+-------+------+---------+-----------------------------------------------------------------------------------+-----+--------+---------------------+---------------------+

描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
mysql> SELECT * FROM `tb_item_desc` where item_id=153156317952887;

+-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------+---------------------+---------------------+

| item_id | item_desc


| created | updated |
+-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------+---------------------+---------------------+
| 153156317952887 | <p>
<span style="font-family:&quot;background-color:#FFFFFF;">商务投资</span><span style="font-family:&quot;background-color:#FFFFFF;">商务投资</span><span style="font-family:&quot;background-color:#FFFFFF;">商务投资</span><span style="font-fami
y:&quot;background-color:#FFFFFF;">商务投资</span><span style="font-family:&quot;background-color:#FFFFFF;">商务投资</span><span style="font-family:&quot;background-color:#FFFFFF;"></span><span style="font-family:&quot;background-color:#FFFFFF;"></s
an><span style="font-family:&quot;background-color:#FFFFFF;"></span>
</p>
<p>
<span style="font-family:&quot;background-color:#FFFFFF;"><img src="http://192.168.220.133/images/2018/07/14/c23109f3-c223-4ffc-b58f-b5d286114a4a.png" alt="" /><br />
</span>
</p> | 2018-07-14 18:13:00 | 2018-07-14 18:13:00 |
+-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Java项目实战 - 图片Server管理和图片上传

Posted on 2018-07-16 | In Java |

要分布式的环境中,一般会配置一个专门的图片Server。

图片服务器

  • Nginx作为http服务
  • ftp上传图片 - linux自带:vsftpd。

Nginx和vsftpd都需要安装配置,不做说明。

配置信息

文件上传解析器

1
2
3
4
5
6
7
8
<!-- 定义文件上传解析器 -->
<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>

创建公共Properties

在properties下创建resource.properties文件

1
2
3
4
5
6
7
8
9
#FTP配置
FTP_IP=192.168.220.133
FTP_PORT=21
FTP_USERNAME=ftpuser
FTP_PASSWORD=ftpuser
FTP_BASE_PATH=/home/ftpuser/www/images

#图片Several配置
IMAGE_BASE_PATH=http://192.168.220.133/images

并修改<context:property-placeholder location="classpath:properties/db.properties" /> to <context:property-placeholder location="classpath:properties/*.properties" />

Service

封装了一个公共的File Upload的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@Service
public class PictureServiceImpl implements PictureService {

//利用这种方式来取resource.properties的配置
@Value("${FTP_IP}")
private String FTP_IP;
@Value("${FTP_PORT}")
private Integer FTP_PORT;
@Value("${FTP_USERNAME}")
private String FTP_USERNAME;
@Value("${FTP_PASSWORD}")
private String FTP_PASSWORD;
@Value("${FTP_BASE_PATH}")
private String FTP_BASE_PATH;
@Value("${IMAGE_BASE_PATH}")
private String IMAGE_BASE_PATH;


@Override
public Map uploadPicture(MultipartFile uploadFile) {
Map resultMap = new HashMap<>();

try {
// 生成新文件名
String oldname = uploadFile.getOriginalFilename();
String newname = UUID.randomUUID().toString();
newname = newname + oldname.substring(oldname.lastIndexOf("."));

//上传图片
String filepath = new DateTime().toString("/yyyy/MM/dd");
boolean result = FtpUtil.uploadFile(FTP_IP, FTP_PORT, FTP_USERNAME, FTP_PASSWORD, FTP_BASE_PATH,
filepath, newname, uploadFile.getInputStream());
if(!result){
resultMap.put("error", 1);
resultMap.put("message", "File upload failed");
return resultMap;
}
resultMap.put("error", 0);
resultMap.put("url", IMAGE_BASE_PATH + filepath + "/" + newname);
return resultMap;

} catch (Exception e) {
resultMap.put("error", 1);
resultMap.put("message", "File upload failed");
return resultMap;
}
}
}

Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
public class PictureController {

@Autowired
private PictureService pictureService;

@RequestMapping("/pic/upload")
@ResponseBody
public String pictureUpload(MultipartFile uploadFile){
Map result = pictureService.uploadPicture(uploadFile);
return JsonUtils.objectToJson(result);//处理浏览器兼容性
}
}

运行结果

Java项目实战 - 商品类目选择

Posted on 2018-07-15 | In Java |

Dao

逆向工程已经实现了Mapper,不需要再做修改。

Service

接收parentId参数。
调用dao查询Tree节点,返回一个EasyUITreeNode支持的数据格式的Tree节点。
pojo:
把它放到izheyi-manager-common里,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class EasyUiTreeNode {
public long id;
public String text;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String state;
}

接口类:

1
2
3
4
5
public interface ItemCategoryService {

List<EasyUiTreeNode> getItemCategoryNode(long parentId);

}

实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Service
public class ItemCategoryServiceImpl implements ItemCategoryService {
@Autowired
private TbItemCatMapper itemCategoryMapper;

@Override
public List<EasyUiTreeNode> getItemCategoryNode(long parentId) {
// Search
TbItemCatExample example = new TbItemCatExample();
Criteria criteria = example.createCriteria();
criteria.andParentIdEqualTo(parentId);

//返回结果列表
List<TbItemCat> list = itemCategoryMapper.selectByExample(example);

//转换成EasyUiTree
List<EasyUiTreeNode> result = new ArrayList<EasyUiTreeNode>();
for (TbItemCat tbItemCat : list) {
EasyUiTreeNode node = new EasyUiTreeNode();
node.setId(tbItemCat.getId());
node.setText(tbItemCat.getName());
node.setState(tbItemCat.getIsParent()?"closed":"open");

result.add(node);
}
return result;
}
}

Controller

接收页面传递过来的参数id。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Controller
public class ItemCategoryController {
@Autowired
private ItemCategoryService itemCategoryService;

@RequestMapping("/item/cat/list")
@ResponseBody
public List<EasyUiTreeNode> getItemCategoryNode(@RequestParam(value="id", defaultValue="0") long parentId){

List<EasyUiTreeNode> result = itemCategoryService.getItemCategoryNode(parentId);
return result;
}
}

运行结果

1…101112…40
唐胡璐

唐胡璐

i just wanna live while i am alive

393 posts
42 categories
74 tags
RSS
LinkedIn Weibo GitHub E-Mail
Creative Commons
© 2022 唐胡璐
Powered by Hexo
|
Theme — NexT.Pisces v5.1.4