1. 今日大纲

  1. 实现首页的大广告位功能
  2. 实现内容管理系统
    1. 首页的大广告

      1. 什么是大广告

JS效果:

  1. 点击下面的序号选择查询哪个广告
  2. 自动切换
  3. 点击图片查询具体的页面

以上是由前端团队来开发。

  1. 数据结构

说明:必须提供6条数据,才能显示效果。

  1. 如何实现?

方案一:

  1. 在后台系统中创建一张表,存储大广告位的广告数据
  2. 在后台系统中对该表进行CRUD
  3. 后台系统对外提供接口服务
  4. 前台系统调用后台系统的提供的接口服务,即可获取到数据
  5. 前台系统获取到数据后,封装成前端所需要的数据结构,功能即可实现

方案二:

  1. 将首页显示的广告都抽象的看作是内容
  2. 在后台系统中创建一张内容表
  3. 创建一个内容分类表用于区分内容的分类
  4. 后台系统对内容表以及分类表进行CRUD
  5. 对外提供接口服务
  6. 前端系统通过接口获取数据,进行封装,即可实现
  1. 内容管理系统(CMS)

  1. 内容分类管理

    1. 表结构

      1. 内容分类表

  1. 内容表

应该有的字段:

  1. 图片
  2. 连接
  3. 标题
  4. 子标题

表结构中字段是否添加索引判断依据是什么? -- 字段是否是查询条件或者是排序条件。

是否将所有的字段都添加索引,来加快查询? -- 不行的

  1. 索引会占用存储空间,索引越多,使用的存储空间越多
  2. 插入数据,存储索引也会消耗时间,索引越多,插入数据的速度越慢
    1. 实现

      1. 创建pojo、mapper、service、controller

略。

  1. 内容分类管理

创建根节点:

  1. 分类列表查询

效果:

  1. 节点的右键菜单

定义菜单:

右键触发菜单显示:

具体的菜单事件:

  1. 新增事件

JS实现:

按下回车,编辑完成事件:

后台实现:

Controller:

  1. 重命名

JS实现:

后端实现:

  1. 删除

JS实现:

过滤器:

后端实现:

Controller:

Service:

public void deleteAll(ContentCategory contentCategory) {

List<Object> ids = new ArrayList<Object>();

ids.add(contentCategory.getId());

// 递归查找该节点下的所有子节点id

this.findAllSubNode(ids, contentCategory.getId());

super.deleteByIds(ids, ContentCategory.class, "id");

// 判断该节点是否还有兄弟节点,如果没有,修改父节点的isParent为false

ContentCategory record = new ContentCategory();

record.setParentId(contentCategory.getParentId());

List<ContentCategory> list = super.queryListByWhere(record);

if (null == list || list.isEmpty()) {

ContentCategory parent = new ContentCategory();

parent.setId(contentCategory.getParentId());

parent.setIsParent(false);

super.updateSelective(parent);

}

}

private void findAllSubNode(List<Object> ids, Long pid) {

ContentCategory record = new ContentCategory();

record.setParentId(pid);

List<ContentCategory> list = super.queryListByWhere(record);

for (ContentCategory contentCategory : list) {

ids.add(contentCategory.getId());

// 判断该节点是否为父节点,如果是,继续调用该方法查找子节点

if (contentCategory.getIsParent()) {

// 开始递归

findAllSubNode(ids, contentCategory.getId());

}

}

}

  1. 存在的问题(TODO)

在Controller中实现数据库的操作,不在同一个事务中,需要将所有的操作移动至Service中完成。

  1. 内容管理

    1. 功能

  1. 选择内容分类加载数据

  1. 新增内容

校验,必须选中内容分类才能创建内容数据:

新增内容页面:

  1. 点击提交事件

  1. 后端实现

  1. 测试

  1. 查询内容列表

    1. JS实现

  1. Controller实现

  1. Service

  1. Mapper

  1. Mapper.xml

  1. 开启驼峰映射

<settings>

<!-- 开启驼峰自动映射 -->

<setting name="mapUnderscoreToCamelCase" value="true"/>

</settings>

  1. 在Spring和Mybatis的整合文件中读取Mapper.xml

  1. 效果

  1. 对外的接口服务

将ContentController拷贝到api包下,对外提供接口服务:

实现:

@RequestMapping("api/content")

@Controller

public class ApiContentController {

@Autowired

private ContentService contentService;

/**

* 根据内容分类id查询分类列表

*

* @param categoryId

* @param page

* @param rows

* @return

*/

@RequestMapping(method = RequestMethod.GET)

public ResponseEntity<EasyUIResult> queryListByCategoryId(@RequestParam("categoryId") Long categoryId,

@RequestParam(value = "page", defaultValue = "1") Integer page,

@RequestParam(value = "rows", defaultValue = "10") Integer rows) {

try {

EasyUIResult easyUIResult = this.contentService.queryListByCategoryId(categoryId, page, rows);

return ResponseEntity.ok(easyUIResult);

} catch (Exception e) {

e.printStackTrace();

}

return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);

}

}

测试:

  1. 访问接口服务的方式

方式有2种:

  1. js访问
    1. 有跨域 -- jsonp解决
    2. 无跨域 -- ajax解决
  2. Java代码访问
    1. Httpclient
    1. Httpclient

  1. 导入依赖

  1. DoGET

  1. 带有参数的GET请求

  1. DoPOST

  1. 带有参数的POST请求

public static void main(String[] args) throws Exception {

// 创建Httpclient对象

CloseableHttpClient httpclient = HttpClients.createDefault();

// 创建http POST请求

HttpPost httpPost = new HttpPost("http://www.oschina.net/search");

// 伪装成浏览器

httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36");

个post参数,一个是scope、一个是q

List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);

parameters.add(new BasicNameValuePair("scope", "project"));

parameters.add(new BasicNameValuePair("q", "java"));

parameters.add(new BasicNameValuePair("fromerr", "7nXH76r7"));

// 构造一个form表单式的实体

UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);

// 将请求实体设置到httpPost对象中

httpPost.setEntity(formEntity);

CloseableHttpResponse response = null;

try {

// 执行请求

response = httpclient.execute(httpPost);

if (response.getStatusLine().getStatusCode() == 200) {

String content = EntityUtils.toString(response.getEntity(), "UTF-8");

System.out.println(content);

}

} finally {

if (response != null) {

response.close();

}

httpclient.close();

}

}

  1. 连接管理器

注意

  1. 定期关闭无效连接

public class ClientEvictExpiredConnections {

public static void main(String[] args) throws Exception {

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();

// 设置最大连接数

cm.setMaxTotal(200);

// 设置每个主机地址的并发数

cm.setDefaultMaxPerRoute(20);

new IdleConnectionEvictor(cm).start();

}

public static class IdleConnectionEvictor extends Thread {

private final HttpClientConnectionManager connMgr;

private volatile boolean shutdown;

public IdleConnectionEvictor(HttpClientConnectionManager connMgr) {

this.connMgr = connMgr;

}

@Override

public void run() {

try {

while (!shutdown) {

synchronized (this) {

wait(5000);

// 关闭失效的连接

connMgr.closeExpiredConnections();

}

}

} catch (InterruptedException ex) {

// 结束

}

}

public void shutdown() {

shutdown = true;

synchronized (this) {

notifyAll();

}

}

}

}

  1. 设置请求参数

  1. Httpclient和Spring的整合

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"

xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd

    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd

    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

<!-- 定义连接管理器 -->

<bean id="httpClientConnectionManager"

class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">

<property name="maxTotal" value="${http.maxTotal}" />

<property name="defaultMaxPerRoute" value="${http.defaultMaxPerRoute}" />

</bean>

<!-- httpclient的构建器 -->

<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder">

<property name="connectionManager" ref="httpClientConnectionManager" />

</bean>

<!-- 定义Httpclient对象 -->

<!-- 该对象是多例的 -->

<bean class="org.apache.http.impl.client.CloseableHttpClient"

factory-bean="httpClientBuilder" factory-method="build" scope="prototype">

</bean>

<!-- 请求参数的构建器 -->

<bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig.Builder">

<!-- 创建连接的最长时间 -->

<property name="connectTimeout" value="${http.connectTimeout}" />

<!-- 从连接池中获取到连接的最长时间 -->

<property name="connectionRequestTimeout" value="${http.connectionRequestTimeout}" />

<!-- 数据传输的最长时间 -->

<property name="socketTimeout" value="${http.socketTimeout}" />

<!-- 提交请求前测试连接是否可用 -->

<property name="staleConnectionCheckEnabled" value="${http.staleConnectionCheckEnabled}" />

</bean>

<!-- 定义请求参数对象 -->

<bean class="org.apache.http.client.config.RequestConfig"

factory-bean="requestConfigBuilder" factory-method="build" />

<!-- 定期关闭无效连接 -->

<bean class="com.taotao.web.httpclient.IdleConnectionEvictor">

<constructor-arg index="0" ref="httpClientConnectionManager" />

</bean>

</beans>

  1. 封装ApiService

package com.taotao.web.service;

import java.io.IOException;

import java.net.URISyntaxException;

import java.util.ArrayList;

import java.util.List;

import java.util.Map;

import org.apache.http.NameValuePair;

import org.apache.http.ParseException;

import org.apache.http.client.ClientProtocolException;

import org.apache.http.client.config.RequestConfig;

import org.apache.http.client.entity.UrlEncodedFormEntity;

import org.apache.http.client.methods.CloseableHttpResponse;

import org.apache.http.client.methods.HttpGet;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.client.utils.URIBuilder;

import org.apache.http.impl.client.CloseableHttpClient;

import org.apache.http.message.BasicNameValuePair;

import org.apache.http.util.EntityUtils;

import org.springframework.beans.BeansException;

import org.springframework.beans.factory.BeanFactory;

import org.springframework.beans.factory.BeanFactoryAware;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.taotao.web.httpclient.HttpResult;

@Service

public class ApiService implements BeanFactoryAware{

@Autowired

private RequestConfig requestConfig;

private BeanFactory beanFactory;

/**

* 指定GET请求,返回:null,请求失败,String数据,请求成功

*

* @param url

* @return

* @throws ClientProtocolException

* @throws IOException

*/

public String doGet(String url) throws ClientProtocolException, IOException {

// 创建http GET请求

HttpGet httpGet = new HttpGet(url);

httpGet.setConfig(requestConfig);

CloseableHttpResponse response = null;

try {

// 执行请求

response = getHttpClient().execute(httpGet);

if (response.getStatusLine().getStatusCode() == 200) {

return EntityUtils.toString(response.getEntity(), "UTF-8");

}

} finally {

if (response != null) {

response.close();

}

}

return null;

}

/**

* 带有参数的GET请求,返回:null,请求失败,String数据,请求成功

*

* @param url

* @param params

* @return

* @throws ClientProtocolException

* @throws IOException

* @throws URISyntaxException

*/

public String doGet(String url, Map<String, String> params) throws ClientProtocolException, IOException,

URISyntaxException {

URIBuilder builder = new URIBuilder(url);

for (Map.Entry<String, String> entry : params.entrySet()) {

builder.setParameter(entry.getKey(), entry.getValue());

}

return this.doGet(builder.build().toString());

}

/**

* 带有参数的POST请求

*

* @param url

* @param params

* @return

* @throws ParseException

* @throws IOException

*/

public HttpResult doPost(String url, Map<String, String> params) throws ParseException, IOException {

// 创建http POST请求

HttpPost httpPost = new HttpPost(url);

httpPost.setConfig(requestConfig);

if (null != params) {

// 设置post参

List<NameValuePair> parameters = new ArrayList<NameValuePair>(0);

for (Map.Entry<String, String> entry : params.entrySet()) {

parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));

}

// 构造一个form表单式的实体

UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);

// 将请求实体设置到httpPost对象中

httpPost.setEntity(formEntity);

}

CloseableHttpResponse response = null;

try {

// 执行请求

response = getHttpClient().execute(httpPost);

return new HttpResult(response.getStatusLine().getStatusCode(), EntityUtils.toString(

response.getEntity(), "UTF-8"));

} finally {

if (response != null) {

response.close();

}

}

}

/**

* 没有参数的POST请求

*

* @param url

* @return

* @throws ParseException

* @throws IOException

*/

public HttpResult doPost(String url) throws ParseException, IOException {

return this.doPost(url, null);

}

private CloseableHttpClient getHttpClient(){

//通过Bean工厂获取bean,保证HttpClient对象是多例

return this.beanFactory.getBean(CloseableHttpClient.class);

}

@Override

public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

this.beanFactory = beanFactory;

}

}

  1. 实现大广告

    1. 访问后台系统接口获取数据

  1. 将json数据保存到模型数据中

  1. 通过EL表达式输出到页面

  1. 测试

效果:

  1. 实现小广告

    1. 分析

  1. 实现

    1. Controller

  1. Service

  1. 效果

作业:实现淘淘快报。

  1. 优化实现

淘淘商城_day04_课堂笔记的更多相关文章

  1. 淘淘商城_day11_课堂笔记

    今日大纲 发布前的准备 实施发布 一部分是由我来发布 一部分是由你们来发布 讲解分布式部署架构 测试 功能测试 压力测试 项目实战的准备以及分组 分组 抽取功能 讲解所需要开发的功能 项目部署上线流程 ...

  2. 淘淘商城_day01_课堂笔记

    今日大纲 聊聊电商行业 电商行业发展 11.11 2015双11: 2016年: 预测:2017年的双11交易额将达到:1400亿 电商行业技术特点 淘淘商城简介 淘淘商城的前身 电商行业的概念 B2 ...

  3. 淘淘商城_day02_课堂笔记

    今日大纲 学习Nginx的使用 实现商品的管理 新增商品 查询商品列表 编辑商品 删除商品 上架和下架商品 学习nginx 开发阶段中的环境 开发环境:自己的电脑 测试环境:提供给测试人员使用的环境 ...

  4. 淘淘商城_day10_课堂笔记

    今日大纲 Dubbo入门学习 使用dubbo优化单点登录系统 系统间服务调用方式 浏览器直接访问 浏览器发起请求,通过ajax或jsonp方式请求: Httpclient方式 系统与系统之间通过Htt ...

  5. 淘淘商城_day09_课堂笔记

    今日大纲 实现购物车 基于Mysql实现读写分离 购物车 需求描述 用户可以在登录状态下将商品添加到购物车 用户可以在未登录状态下将商品添加到购物车 用户可以使用购物车一起结算下单 用户可以查询自己的 ...

  6. 淘淘商城_day08_课堂笔记

    今日大纲 问题,如何实现商品数据的同步? 学习MQ(消息队列) 搭建RabbitMQ的环境 学习RabbitMQ的队列 学习Spring-Rabbit 使用RabbitMQ完成商品数据的同步 如何实现 ...

  7. 淘淘商城_day07_课堂笔记

    今日大纲 讲解订单系统 基于订单系统完成下单功能的开发 使用Solr完成商品的搜索功能 订单系统 说明:订单系统只是做讲解,不做开发. 导入taotao-order 表结构 订单表: 订单商品表: 疑 ...

  8. 淘淘商城_day05_课堂笔记

    今日大纲 学习Redis 使用Redis完成项目中缓存需求 实现商品详情页功能 缓存的需求 大广告位数据无需每次查询后台系统的接口,可以在前台系统添加缓存,提高访问首页的速度. 商品类目的数据也可以缓 ...

  9. 淘淘商城_day06_课堂笔记

    今日大纲 实现单点登录系统 基于单点登录系统实现,用户的注册和登录 商品数据同步问题 问题 后台系统中将商品修改,前台系统没有进行数据的同步,导致前端系统不能够实时显示最新的数据. 解决 后台系统中商 ...

随机推荐

  1. 数据库中的null问题

    在数据库中有些列的值可以为null,这一篇,我们围绕数据库中的null来讲述. 1. null与 “”.0的区别   数据库中的null表示——不知道,“”——一个空字符串,0则是一个数值.  所以n ...

  2. UIView的生命周期和layout方法总结

    生命周期 1. loadView 什么时候调用? 每次访问UIViewController的view时候并且view == nil时候调用. 如何实现? 1> 如果在初始化UIViewContr ...

  3. C语言总结2

    12).预处理指令 1. 什么叫做预处理代码. 以#开头的代码就是预处理代码  #warning #import 2. 手写1个C程序的步骤.(面试题) 1>编写代码 2>编译 1)执行. ...

  4. C语言之字符集、ASCII码和sizeof运算符

    一 字符集和ASCII码 结论:字符本质上也是一个整数,每个字符都有唯一一个与之对应的整数, 比如说小写的a对应97,b对应98,c对应99,大写的A对应65,B对应66,C对应67 所以字符对应的那 ...

  5. Mybatis原理图

    Mybatis原理图 MyBatis 是一个基于Java的持久层框架.它提供的持久层框架包括SQL Maps和Data Access Objects(DAO). MyBatis 是支持普通 SQL查询 ...

  6. Android Studio报错 Error: A library uses the same package as this project

    今天在导入一个项目的时候,as报错 Error: A library uses the same package as this project 经过百度Google 发现解决办法:在modules的 ...

  7. Qt 富文本处理

    富文本处理 所有的类围绕 QTextDocument 展开, 它保证了用户可以创建和修改 富文本块, 而无须定义中间语言.一个 QTextDocument 可以通过两个接口操作, 一个是用于编辑的 C ...

  8. [ An Ac a Day ^_^ ] [kuangbin带你飞]专题八 生成树 UVA 10600 ACM Contest and Blackout 最小生成树+次小生成树

    题意就是求最小生成树和次小生成树 #include<cstdio> #include<iostream> #include<algorithm> #include& ...

  9. 关于angularjs+typeahead的整合

    和angularjs-xeditable的基本相似,主要区别在于前者用于普通input中,后者用于xeditable中 在angularjs-xeditable需要自动提示的地方要用e-uib-typ ...

  10. Python学习笔记——基础篇【第六周】——hashlib模块

    常用模块之hashlib模块 用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法 import ...