|
易购商城 |
第三天 |
目 录
1 课程计划 3
2 搭建前台系统 3
2.1 前台系统架构 3
2.1.1 分层架构的好处 3
2.2 搭建服务层系统 4
2.2.1 系统简介 4
2.2.2 技术选择 4
2.2.3 配置步骤 4
2.3 搭建门户系统 13
2.3.1 系统简介 13
2.3.2 技术选择 14
2.3.3 配置步骤 14
3 首页导航菜单实现 20
3.1 实现流程 20
3.2 跨越请求 21
3.2.1 什么是跨域(两个不同系统之间的访问、调用) 21
3.2.2 Ajax跨域请求的缺陷 21
3.2.3 解决方案:jsonp跨域 23
3.3 首页导航菜单实现 25
3.3.1 第一部分:在rest工程中开发导航菜单接口 25
3.3.2 第二部分:在portal工程中调用导航菜单接口 31
4 CMS系统 32
4.1 概念 32
4.2 CMS系统实现 32
4.2.1 思路 32
4.2.2 数据库表关系 33
4.2.3 内容分类实现 33
4.2.4 内容管理实现 44
5 首页大广告实现 53
5.1 需求 53
5.2 实现流程 53
5.3 第一部分:REST系统接口实现 54
5.3.1 第一步:确定代码结构 54
5.3.2 第二步:定义接口规则 55
5.3.3 第三步:创建ContentService接口及其实现类 55
5.3.4 第四步:创建ContentController类 56
5.4 第二部分:远程接口调用方式HttpClient 56
5.4.1 Httpclient简介 56
5.4.2 HttpClient测试 57
5.4.3 httpclient常见问题及解决方案 62
5.4.4 封装通用工具类HttpClientUtils 62
5.5 第三部分:portal系统实现 67
5.5.1 第一步:前端js实现 67
5.5.2 第二步:确定代码结构 67
5.5.3 第三步:创建大广告位ADItem类 68
5.5.4 第四步:创建resourse.properties配置文件 69
5.5.5 第五步:创建ContentService接口及其实现类 69
5.5.6 第六步:测试 71
课程计划
(1)搭建前台系统。
(2)完成首页导航菜单。(学习jsonp)
(3)完成CMS内容管理系统。
(4)完成首页大广告位投放。(学习Httpclient)
- 搭建前台系统
- 前台系统架构
在互联网系统开发当中,我们一般都是采用了分层的方式来架构系统,即:
(1)门户层(门户系统):网站的入口
i、渲染视图,提供用户访问的页面。
ii、不查询数据库,数据来自对远程服务(接口)的调用。
(2)服务层:基于restful,以接口的形式对外提供公共的服务。
i、连接数据库,返回json格式的数据。
-
-
- 分层架构的好处
-
(1)、有利于系统的维护和拓展。
(2)、有利于SOA服务治理的基础。
-
- 搭建服务层系统
- 系统简介
- 搭建服务层系统
基于RESTful实现。以接口的形式,对外提供公共的服务。(比如购物车、导航菜单、搜索、订单等等)
RESTful是一种接口设计理念,即:
(1)不同的请求方式,对应不同的业务类型:
GET :查询
POST :添加
PUT :更新
DELETE: 删除
(2)返回json格式数据。
-
-
- 技术选择
-
核心框架:Spring+SpringMVC+Mybatis-plus
数 据 库:MySQL
前端框架:无
-
-
- 配置步骤
-
思路:(1)创建项目,导入jar依赖。
(2)整合SSM框架。
-
-
-
- 第一步:创建maven项目(war)模型
-
-
注意:(1)项目继承ego-project。
(2)使用maven module创建项目
-
-
-
- 第二步:导入jar依赖
-
-
导包说明:
(1)ego-base子工程
(2)Spring核心包
(3)SpringMVC相关包
(4)AOP相关包
(5)JDBC、事物相关包
(6)Mybatis-plus及整合包
(7)JSON依赖包
导入插件:Tomcat插件(开发阶段,启动项目,对外发布接口)
<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>cn.gzsxt.ego</groupId> <artifactId>ego-project</artifactId> <version>1.0</version> </parent> <groupId>cn.gzsxt.ego</groupId> <artifactId>ego-rest</artifactId> <version>1.0</version> <packaging>war</packaging>
<dependencies> <dependency> <groupId>cn.gzsxt.ego</groupId> <artifactId>ego-base</artifactId> <version>1.0</version> </dependency> <!-- 整合SSM,导入spring、springmvc、mybatis相关依赖 --> <!-- 导入spring核心依赖 4+1 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <!-- 导入spirng-jdbc+事物 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <!-- 导入事物的依赖 :切面 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency>
<!-- 导入springmvc相关依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency>
<!-- 导入mybatis相关依赖 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> </dependency>
<!-- 导入jdbc、连接池依赖 --> <!-- MySql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- 连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <!-- Jackson Json处理工具包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> </dependencies> <build> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <port>8081</port> <path>/</path> <uriEncoding>UTF-8</uriEncoding> </configuration> </plugin> </plugins> </build> </project> |
-
-
-
- 第三步:创建web.xml文件
-
-
说明:可以从ego-manager工程中拷贝,修改<url-pattern>即可。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_2_5.xsd ">
<!-- 配置编码过滤器,防止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>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-*.xml</param-value> </init-param> <!-- 项目启动的时候,就加载spring容器 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name>
<!-- 所有请求rest服务层系统的请求,都必须在url加上/rest前缀,好处:方便做维护。 --> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app> |
-
-
-
- 第四步:整合SSM框架
-
-
整合中所需要的配置文件,均可从ego-manager工程中拷贝,修改局部的配置即可。
-
-
-
-
- Step1:Spring整合SpringMVC
-
-
-
创建spring-mvc.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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<!-- 开启注解扫描 --> <context:component-scan base-package="cn.gzsxt.rest"/> <!-- 开启注解驱动 --> <mvc:annotation-driven/> </beans> |
-
-
-
-
- Step2:mybatis-plus整合spring
-
-
-
在这里,我们一定要有一个概念:任何持久层框架和Spring的整合,都是为了使用Spring的事物代理。
(1)创建resource.properties文件,配置数据库连接信息如下:
#配置数据源 db.driver=com.mysql.jdbc.Driver db.url=jdbc:mysql://localhost:3306/ego db.username=root db.password=gzsxt |
(2)创建spring-data.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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<context:property-placeholder file-encoding="utf-8" location="classpath:resource.properties"/>
<!-- 1、创建数据源 --> <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${db.driver}"/> <property name="url" value="${db.url}"/> <property name="username" value="${db.username}"/> <property name="password" value="${db.password}"/> <property name="maxActive" value="20"/> <property name="minIdle" value="5"/> </bean>
<!-- 2、mybatis-plus整合Spring 任何的数据库的框架,要使用spring的事物代理,必须使用spring提供的数据源,必须整合spring才可以使用 --> <bean name="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"> <!-- 加载数据源 --> <property name="dataSource" ref="dataSource"/>
<!-- 指定pojo目录 --> <property name="typeAliasesPackage" value="cn.gzsxt.base.pojo"/>
<!-- 配置mybatis-plus插件 --> <property name="plugins"> <list> <!-- 配置分页插件 --> <bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"/>
<!-- 配置拦截器属性 --> <bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor"> <!-- 配置sql响应时间,开发阶段方便做调优 --> <property name="maxTime" value="1000"/> <property name="format" value="true"/>
</bean> </list> </property>
<!-- 配置mybatis-plus全局策略 --> <property name="globalConfig" ref="globalConfiguration"></property>
</bean>
<!-- 3、配置mybatis的动态代理 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
<property name="basePackage" value="cn.gzsxt.base.mapper"></property>
</bean>
<!-- 配置mybatis-plus全局属性 --> <!-- 定义 MybatisPlus 的全局策略配置--> <bean id ="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration"> <!-- 在 2.3 版本以后,dbColumnUnderline 默认值是 true,即pojo属性开启驼峰标识 --> <property name="dbColumnUnderline" value="true"></property> <!-- 全局的主键策略 --> <!-- AUTO->`0`("数据库ID自增") INPUT->`1`(用户输入ID") ID_WORKER->`2`("全局唯一ID") UUID->`3`("全局唯一ID") --> <property name="idType" value="0"></property> <!-- 全局的表前缀策略配置 --> <property name="tablePrefix" value="tb_"></property> </bean>
<!-- 4、配置事物管理器 --> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
<!-- 5、开启注解声明式事物 --> <tx:annotation-driven/> </beans>
|
-
-
-
- 第五步:整合测试
-
-
在这里我们使用静态数据(category.json),来模拟导航菜单接口的实现。
(1)拷贝category.json文件到webapp目录下。
(2)更新项目、安装到本地仓库(updata、maven clean、maven install)
(3)启动项目
查看控制台,启动成功!!!
(4)浏览器访问,地址:http://localhost:8081/category.json,整合成功!!!
-
- 搭建门户系统
- 系统简介
- 搭建门户系统
简单来说就是网站的入口,提供用户浏览、下单的操作页面。
门户系统不直接调用数据库,而是通过服务系统提供的接口获取数据。电商、互联网行业开发都是面向服务开发。
-
-
- 技术选择
-
核心框架:Spring+SpringMVC
数 据 库:无
前端技术:jquery、ajax、css+div、easyui等
-
-
- 配置步骤
-
思路:(1)创建项目
(2)框架整合
-
-
-
- 第一步:创建maven项目(war模型)
-
-
注意:(1)继承ego-project工程
(2)使用maven module创建子系统
-
-
-
- 第二步:导入jar依赖
-
-
在门户系统中,不直接查询数据库,所以不需要导入数据库相关的jar包。
在门户系统中,用户能够搜索、浏览商品,提交订单等,所以需要添加jsp视图相关依赖。
<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>cn.gzsxt.ego</groupId> <artifactId>ego-parent</artifactId> <version>1.0</version> </parent> <groupId>cn.gzsxt.ego</groupId> <artifactId>ego-portal</artifactId> <version>1.0</version> <packaging>war</packaging>
<dependencies> <dependency> <groupId>cn.gzsxt.ego</groupId> <artifactId>ego-base</artifactId> <version>1.0</version> </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> <!-- 导入spring核心依赖 4+1 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <!-- 导入springmvc相关依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency>
<!-- Jackson Json处理工具包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> </dependencies> <build> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <port>8082</port> <path>/</path> <uriEncoding>UTF-8</uriEncoding> </configuration> </plugin> </plugins> </build> </project> |
-
-
-
- 第三步:创建web.xml文件
-
-
可以从ego-rest工程拷贝,修改<url-parten>配置
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_2_5.xsd "> <welcome-file-list> <welcome-file>index.html</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>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-*.xml</param-value> </init-param> <!-- 项目启动的时候,就加载spring容器 --> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>dispatcherServlet</servlet-name>
<!-- 把请求路径伪静态话,方便做seo搜索引擎优化,有利于做网站推广 --> <url-pattern>*.html</url-pattern> </servlet-mapping> </web-app> |
-
-
-
- 第四步:导入jsp页面、静态资源
-
-
说明:(1)静态资源放在/webapp目录
(2)jsp放到/WEB-INF/JSP目录下
-
-
-
- 第五步:Spring整合SpringMVC
-
-
从ego-rest工程拷贝,修改部分配置即可。
<?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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
<!-- 开启注解扫描 --> <context:component-scan base-package="cn.gzsxt.portal"/> <!-- 开启注解驱动 --> <mvc:annotation-driven/>
<!-- 由于jsp存放路径在WEB-INF下面,默认视图解析器解析不到,需要自己配一个视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"></property> <property name="suffix" value=".jsp"></property> </bean>
</beans> |
-
-
-
- 第六步:整合测试
-
-
需求:访问门户系统首页。
(1)创建PageController类
package cn.gzsxt.portal.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
public class PageController {
@RequestMapping("/index") public String showIndex(){
return "index"; } } |
(2)更新项目、安装到本地仓库。(update、clean、install)
(3)启动项目
(4)访问首页,地址:http://localhost:8082
前台系统搭建成功!!!
- 首页导航菜单实现
说明:首页导航菜单,是通过异步加载实现的。
好处:只有当展开导航菜单时,才会发送请求,从而节约cpu资源。
-
- 实现流程
需要解决的问题:
(1)在rest系统中发布接口,封装导航菜单成json格式数据。
(2)在portal系统中,远程请求接口(跨域请求)。
-
- 跨越请求
- 什么是跨域(两个不同系统之间的访问、调用)
- 跨越请求
(1)域名不同,即两个不同的应用。
(2)域名相同,但是端口不同,即同一个应用中的不同子系统。
-
-
- Ajax跨域请求的缺陷
-
在ego-rest系统使用静态数据,模拟Ajax的跨域问题。
-
-
-
- 第一步:在ego-rest中添加category.json文件。(已实现)
- 第二步:在ego-portal中发送ajax请求
-
-
(1)创建testJsonp.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"> <script type="text/javascript" src="/js/jquery-1.6.4.js"></script> <title>Insert title here</title> </head> <body> <textarea id="text" style="width: 1200px; height: 200px;"></textarea> <input type="button" value="测试异步跨越" onclick="testajax()" /> <script type="text/javascript"> function testajax(){ $.ajax({ url:"http://localhost:8081/category.json", type: "GET", success: function (data) { $("#text").val(JSON.stringify(data)); } }); } </script> </body> </html> |
(2)修改PageController,新增访问非首页的方法。
@RequestMapping("/{page}") public String showPage(@PathVariable("page")String page){
return page; } |
-
-
-
- 第三步:测试Ajax跨越
-
-
(1)重启启动ego-portal系统,访问testJsonp.jsp
(2)点击按钮,发送异步请求
测试发现,Ajax跨越请求失败了。
-
-
- 解决方案:jsonp跨域
-
在前面的测试中,我们发现Ajax跨越请求时,json数据被浏览器禁用了。
原因:浏览器禁止远程加载Json数据。(浏览器安全机制)
如何解决呢?
答:使用Jsonp方式。
-
-
-
- Jsonp原理
-
-
Jsonp实现的前提:
浏览器允许跨越加载同源数据。
即在JavaScript脚本中发送请求,就可以远程加载js格式数据。
请求原理:
(1)异步请求的时候,加上一个名为callback的回调函数
(2)在接口中,将返回的json格式数据,伪装成js脚本格式。
(3)得到js格式数据后,提取里面的json数据。
-
-
-
- 测试Jsonp
-
-
(1)修改testJsonp.jsp,指定异步请求为jsonp方式。
<script type="text/javascript"> function testajax(){ $.ajax({ url:"http://localhost:8081/category.json", type: "GET", dataType: "jsonp", //jsonp请求 jsonp:"callbackFunction", //请求参数名 jsonpCallback:"showData", //回调函数名称 success: function (data) { $("#text").val(JSON.stringify(data)); } }); } </script> |
(2)在ego-rest工程中,修改category.json文件,将返回数据包装成js脚本。
(3)再次发送ajax异步请求,使用jsonp方式
结论:(1)jsonp是ajax技术中的一种异步请求方式。
(2)jsonp能实现跨越请求。
(3)jsonp跨越时,需要指定一个回调函数,并使用该函数将返回的数据伪装成js脚本。
(4)获取返回的js脚本后,jsonp自动提取其中的json数据。
-
- 首页导航菜单实现
思路:
(1)在rest工程中,开发接口,返回js格式数据。(参考category.json)
(2)在portal工程中,修改jsonp请求路径。请求rest接口。
-
-
- 第一部分:在rest工程中开发导航菜单接口
- 第一步:定义导航菜单POJO
- 第一部分:在rest工程中开发导航菜单接口
-
导航菜单结构分析。(使用JsonViewer工具查看category.json)
结论:(1)需要定义两个POJO:菜单POJO、父目录节点POJO
(2)导航菜单的数据,是一次加载出来的。
创建菜单Menu类。(ego-base中创建)
package cn.gzsxt.base.pojo;
import java.util.List;
/** * 自定义导航菜单 * @author ccnulyq * */ public class Menu {
private List<?> data; //目录节点
public List<?> getData() { return data; }
public void setData(List<?> data) { this.data = data; }
public Menu() { super(); } } |
创建父目录节点MenuNode类
package cn.gzsxt.base.pojo;
import java.util.List;
/** * 自定义目录节点结构 * @author ccnulyq * */ public class MenuNode {
private String u; //目录的链接
private String n; //目录的名称
private List<?> i; //当请目录的子目录
public MenuNode() { super(); } // 补全get、set方法 } |
(3)重新编译ego-base工程,安装到本地仓库。(maven clean、maven install)
-
-
-
- 第二步:创建ItemCatService接口及其实现类
-
-
package cn.gzsxt.rest.service.impl;
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import cn.gzsxt.base.mapper.ItemCatMapper; import cn.gzsxt.base.pojo.ItemCat; import cn.gzsxt.base.vo.Menu; import cn.gzsxt.base.vo.MenuNode; import cn.gzsxt.rest.service.ItemCatService;
@Service public class ItemCatServiceImpl implements ItemCatService{
@Autowired private ItemCatMapper itemCatMapper;
@Override public Menu initMenu() {
Menu menu = new Menu();
//从返回值Menu的形式上来看,就是把一级目录查询出来即可。因此定义一个查询方法,通过parent_id=0查询一级目录 List nodes = getNodesByParantId(0L); menu.setData(nodes);
return menu; }
//根据父目录的id,查询子目录 private List getNodesByParantId(long parentId) {
Map<String, Object> params = new HashMap<>(); params.put("parent_id", parentId);
List<ItemCat> selectByMap = itemCatMapper.selectByMap(params);
List nodes = new ArrayList<>();
MenuNode node = null; for (ItemCat itemCat : selectByMap) { if(1==itemCat.getIsParent()){ node = new MenuNode();
node.setU("/products/"+itemCat.getId()+".html"); //u : "/products/1.html" node.setN("<a href='/products/"+itemCat.getId()+".html'>"+itemCat.getName()+"</a>"); //n : "<a href='/products/1.html'>图书、音像、电子书刊</a>" node.setI(getNodesByParantId(itemCat.getId())); nodes.add(node);
}else{ nodes.add("/products/"+itemCat.getId()+".html|"+itemCat.getName()); //[3] : "/products/6.html|多媒体图书" } }
return nodes; } } |
-
-
-
- 第三步:创建ItemCatController类
-
-
说明:需要将返回值,包装成js脚本数据。
(1)方式一:手动封装
package cn.gzsxt.rest.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import cn.gzsxt.base.utils.JsonUtils; import cn.gzsxt.base.vo.Menu; import cn.gzsxt.rest.service.ItemCatService;
@Controller public class ItemCatController {
@Autowired private ItemCatService catService;
/* * jsonp方法下,返回值,要使用回调函数来伪装js脚本 * @return */ @RequestMapping(value="/item/all",produces=MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8") @ResponseBody public String getMenu(String callback){ Menu menu = catService.initMenu(); String jsonMenu = JsonUtils.objectToJson(menu); String jsMenu = callback+"("+jsonMenu+")";
return jsMenu; } } |
(2)方式二:使用MappingJacksonValue对象封装
//使用MappingJacksonValue对象包装返回结果,并设置jsonp的回调方法 @RequestMapping("/item/all") @ResponseBody public MappingJacksonValue queryAll(String callback) { //查询分类列表 Menu menu = catService.getMenu(); //包装jsonp MappingJacksonValue jacksonValue = new MappingJacksonValue(menu); //设置包装的回调方法名 jacksonValue.setJsonpFunction(callback); return jacksonValue; } |
-
-
-
- 第四步:测试接口
-
-
在浏览器访问。
地址:http://localhost:8081/rest/item/all?callback=category.getDataService
-
-
- 第二部分:在portal工程中调用导航菜单接口
- 第一步:指定请求方式为jsonp
- 第二部分:在portal工程中调用导航菜单接口
-
(1)修改lib-v1.js文件,指定导航菜单接口地址。
(2)修改lib-v1.js文件,指定请求方式为jsonp。
-
-
-
- 第二步:测试导航菜单
-
-
(1)重启portal工程
(2)访问首页,请求导航菜单
导航菜单开发成功!!!
- CMS系统
- 概念
CMS系统即为内容管理系统。(Content Management System)
所谓的内容,就是出现在网页中的图片、文字、链接等。CMS系统就是用来维护网页中的内容的,实现网页中的内容动态、可变。
比如广告位的投放,秒杀栏、排行榜实时更新等,都需要通过CMS系统来实现。
-
- CMS系统实现
- 思路
- CMS系统实现
(1)、将网页中的内容分类
按照网页的特性分类,然后将每一类网页划分成一个一个独立的区域。
(2)在每一个内容分类下管理、维护各自的内容列表。
-
-
- 数据库表关系
-
CMS系统主要涉及两种表:
(1)内容分类表:tb_content_category(作用:定位)
(2)内容表:tb_content
表之间的对应关系为1-N
-
-
- 内容分类实现
- 需求
- 内容分类实现
-
在后台管理页面,点击内容分类管理菜单,初始化内容分类树结构。该树结构可以添加、修改、删除节点。
-
-
-
- 思路
-
-
(1)初始化内容分类导航树。(这里使用easyui-tree)
(2)对异步树进行维护。(添加节点、删除节点、更新节点)
-
-
-
- 第一部分:初始化内容分类导航树
- 第一步:初始化easyui异步树插件
- 第一部分:初始化内容分类导航树
-
-
-
-
-
-
- 第二步:确定代码结构
-
-
-
Controller | 表现层,负责交互、绑定参数、响应视图 |
Service | 业务层,负责业务逻辑实现(封装树结构) |
Mapper | 持久层,逆向工程生成,不需要开发。 |
-
-
-
-
- 第三步:确定请求响应格式
-
-
-
请求路径 | /content/category/list |
请求方式 | GET请求 |
请求参数 | id=nodeId(首次加载生成一级目录时,默认id=0) |
响应格式 | List<EUTreeNode> (id,text,state:open|closed) |
-
-
-
-
- 第四步:创建ContentCategory类
-
-
-
在公共工程ego-base中创建。
package cn.gzsxt.base.pojo;
import java.util.Date;
import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType;
@TableName(value="tb_content_category") public class ContentCategory {
@TableId(value="id",type=IdType.AUTO) private Long id;
@TableField(value="parent_id") private Long parentId;
private String name;
private int status;
@TableField(value="sort_order") private int sortOrdert;
@TableField(value="is_parent") private byte isParent;
private Date created;
private Date updated;
public ContentCategory() { super(); } // 补全get、set方法 } |
-
-
-
-
- 第五步:创建ContentCategoryMapper接口
-
-
-
在公共工程ego-base中创建。
package cn.gzsxt.base.mapper;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import cn.gzsxt.base.pojo.ContentCategory;
public interface ContentCategoryMapper extends BaseMapper<ContentCategory>{
} |
-
-
-
-
- 第六步:创建ContentCategoryService接口及其实现类
-
-
-
package cn.gzsxt.manager.service.impl;
import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import cn.gzsxt.base.mapper.ContentCategoryMapper; import cn.gzsxt.base.pojo.ContentCategory; import cn.gzsxt.base.vo.EUTreeNode; import cn.gzsxt.base.vo.EgoResult; import cn.gzsxt.manager.service.ContentCategoryService;
@Service public class ContentCategoryServiceImpl implements ContentCategoryService{
@Autowired private ContentCategoryMapper mapper;
@Override public List<EUTreeNode> selectByParentId(Long parentId) {
//定义返回值 List<EUTreeNode> nodes = new ArrayList<>();
//封装查询条件,执行查询 Map<String,Object> columnMap = new HashMap<>();
columnMap.put("parent_id", parentId);
List<ContentCategory> selectByMap = mapper.selectByMap(columnMap);
EUTreeNode node = null;
for (ContentCategory c : selectByMap) { node = new EUTreeNode(); node.setId(c.getId()); node.setText(c.getName());
//三目运算符 node.setState(1==c.getIsParent()?"closed":"open");
nodes.add(node); }
return nodes; } } |
-
-
-
-
- 第七步:创建ContentCategoryController类
-
-
-
package cn.gzsxt.manager.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.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import cn.gzsxt.base.vo.EUTreeNode; import cn.gzsxt.manager.service.ContentCategoryService;
@Controller @RequestMapping("/content/category") public class ContentCategoryController {
@Autowired private ContentCategoryService service;
@RequestMapping(value="/list",method=RequestMethod.GET) @ResponseBody public List<EUTreeNode> selectByParentId(@RequestParam(name="id",defaultValue="0")Long parentId){
return service.selectByParentId(parentId); } } |
-
-
-
-
- 第八步:测试
-
-
-
(1)重新编译ego-manager工程。(clean、install)
(2)重新启动ego-manager。
(3)访问内容分类管理
-
-
-
- 第二部分:添加内容分类节点
- 第一步:前端js实现
- 第二部分:添加内容分类节点
-
-
-
-
-
-
- 第二步:确定代码结构
-
-
-
Controller | 视图层,接收参数,将新增加的节点响应出去 |
Service | 业务层,新增节点、更新父节点 |
Mapper | 持久层,逆向工程生成,不需要开发。 |
-
-
-
-
- 第三步:确定请求响应格式
-
-
-
请求路径 | /content/category/create |
请求方式 | POST |
请求参数 | parentId:node.parentId, name:node.text |
响应格式 | {status:200,data:node} (EgoResult类型) |
-
-
-
-
- 第四步:修改ContentCategoryService及其实现类,新增save方法
-
-
-
注意:先在ContentCategoryService接口中定义save方法
@Transactional(rollbackFor=Exception.class) @Override public EgoResult save(Long parentId, String name) {
ContentCategory temp = new ContentCategory(); temp.setParentId(parentId); temp.setName(name); temp.setIsParent((byte) 0); temp.setSortOrdert(1); temp.setCreated(new Date()); temp.setStatus(1); temp.setUpdated(temp.getCreated());
//mybatis-plus保存对象的时候,已经实现了对象的id自动同步。前提:数据库id是自增。 mapper.insert(temp);
/* * 判断当前添加节点的父节点是否是目录节点。 * * 如果不是,则要修改其状态为父目录结构 */ ContentCategory category = mapper.selectById(parentId); if(0==category.getIsParent()){ category.setIsParent((byte) 1);
mapper.updateById(category); }
return EgoResult.ok(temp); } |
-
-
-
-
- 第五步:修改ContentCategoryController类,定义新增内容分类接口
-
-
-
@RequestMapping(value="/create",method=RequestMethod.POST) @ResponseBody public EgoResult create(Long parentId,String name){ EgoResult result = catService.save(name, parentId);
return result; } |
-
-
-
-
- 第六步:测试
-
-
-
(1)重新编译ego-base工程。(clean、install)
(2)重新启动ego-manager。
(3)新增内容分类节点。
-
-
-
- 第三部分:更新内容分类
- 第一步:前端js实现
- 第三部分:更新内容分类
-
-
-
-
-
-
- 第二步:确定请求响应格式
-
-
-
请求路径 | /content/category/updata |
请求方式 | POST |
请求参数 | id:node.id, name:node.text |
响应格式 | {status:200,data:node} (EgoResult类型) |
-
-
-
-
- 第三步:修改ContentCategoryService及其接口,新增update方法。
-
-
-
注意:先在service接口中定义方法。
@Override public EgoResult updateNode(String name, Long id) { ContentCategory contentCat = new ContentCategory(); contentCat.setName(name); contentCat.setId(id); contentCatMapper.updateById(contentCat);
return EgoResult.ok(); } |
-
-
-
-
- 第四步:修改ContentController类,定义更新的接口
-
-
-
@RequestMapping(value="/update",method=RequestMethod.POST) @ResponseBody public EgoResult updateNode(Long id,String name){ EgoResult result = catService.updateNode(name, id); return result; } |
-
-
-
-
- 第五步:测试
-
-
-
(1)重新编译ego-manager工程。(clean、install)
(2)重新启动ego-manager。
(3)更新内容分类节点。
-
-
-
- 第四部分:删除内容分类
- 第一步:前端js实现
- 第四部分:删除内容分类
-
-
-
-
-
-
- 第二步:确定请求响应格式
-
-
-
请求路径 | /content/category/delete |
请求方式 | POST |
请求参数 | id:node.id, parentId:node.parentId |
响应格式 | {status:200,data:node} (EgoResult类型) |
-
-
-
-
- 第三步:修改ContentCategoryService及其实现类,新增delete方法
-
-
-
@Transactional @Override public EgoResult deleteNode(Long id, Long parentId) {
// 第一步:判断parent_id是否有值 if (parentId == null) { parentId = contentCategoryMapper.selectById(id).getParentId(); }
// 第二步:判断该节点是否是它的父节点的最后一个节点。如果是。那么需要将它的父节点修改为叶节点 EntityWrapper<ContentCategory> wrapper = new EntityWrapper<>(); wrapper.eq("parent_id", parentId); //过滤只查询有效的状态 wrapper.eq("status", 1); List<ContentCategory> categories = contentCategoryMapper.selectList(wrapper); if (categories.size() == 1) { ContentCategory parentCategory = contentCategoryMapper.selectById(parentId); // 父节点修改为叶节点 parentCategory.setIsParent((byte) 0); parentCategory.setUpdated(new Date()); contentCategoryMapper.updateById(parentCategory); }
// 第三步:修改当前节点的状态值,修改为删除状态 ContentCategory category = contentCategoryMapper.selectById(id); category.setStatus(2); category.setUpdated(new Date()); contentCategoryMapper.updateById(category);
return EgoResult.ok(); } |
-
-
-
-
- 第四步:修改ContentCategoryController类,定义delete接口
-
-
-
@RequestMapping(value="/delete",method=RequestMethod.POST) @ResponseBody public EgoResult deleteNode(Long id,Long parentId){ EgoResult result = catService.deleteNode(id, parentId); return result; } |
-
-
- 内容管理实现
- 需求
- 内容管理实现
-
根据内容分类id,查询数据库表tb_content,获取内容列表。
内容分类树使用easyui-tree组件,内容列表使用easyui-datagrid组件。
-
-
-
- 思路
-
-
(1)实现内容列表查询。
(2)在内容分类节点下,维护内容列表。
-
-
-
- 第一部分:内容列表实现
- 第一步:加载easyui-datagrid插件
- 第一部分:内容列表实现
-
-
(1)初始化分类导航树(后台java已实现,见2.2.1.3.2章节)
(2)选中内容分类节点
(3)查询该节点下的内容列表
-
-
-
-
- 第二步:确定代码结构
-
-
-
Controller | 获取分类ID,分页信息,响应列表数据 |
Service | 分页查询逻辑 |
Mapper | 逆向工程生成,不需要开发 |
-
-
-
-
- 第三步:确定请求响应结构
-
-
-
请求路径 | /content/query/list |
请求方式 | GET |
请求参数 | {categoryId:0 , page:1 , rows:20} |
响应格式 | {total:20,rows:dataList} (参见ego-base中的EUDataGridRestult类) |
-
-
-
-
- 第四步:创建Content类
-
-
-
在ego-base工程中创建!
package cn.gzsxt.base.pojo;
import java.util.Date; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType;
@TableName(value="tb_content") public class Content {
@TableId(value="id",type=IdType.AUTO) private Long id;
@TableField(value="category_id") private long categoryId;
private String title;
@TableField(value="sub_title") private String subTitle;
@TableField(value="title_desc") private String titleDesc;
private String url;
private String pic;
private String pic2;
private String content;
private Date created;
private Date updated;
public Content() { super(); }
// 补全get、set方法 } |
-
-
-
-
- 第五步:创建ContentMapper接口
-
-
-
在ego-base工程中创建!
package cn.gzsxt.base.mapper;
import com.baomidou.mybatisplus.mapper.BaseMapper; import cn.gzsxt.base.pojo.Content;
public interface ContentMapper extends BaseMapper<Content>{
} |
-
-
-
-
- 第六步:创建ContentService接口及其实现类
-
-
-
package cn.gzsxt.manager.service.impl;
import java.util.Arrays; import java.util.Date; import java.util.List; import org.apache.ibatis.session.RowBounds; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.baomidou.mybatisplus.mapper.EntityWrapper; import cn.gzsxt.base.mapper.ContentMapper; import cn.gzsxt.base.pojo.Content; import cn.gzsxt.base.vo.EUDataGridResult; import cn.gzsxt.base.vo.EgoResult; import cn.gzsxt.manager.service.ContentService;
@Service public class ContentServiceImpl implements ContentService{
@Autowired private ContentMapper mapper;
@Override public EUDataGridResult listByCatIdAndPage(Long categoryId, int page, int rows) { EUDataGridResult result = new EUDataGridResult(); /* * offset 偏移量 即limit函数中的start * limit 容量 */ RowBounds rowBounds = new RowBounds((page-1)*rows, rows);
EntityWrapper<Content> wrapper = new EntityWrapper<>(); wrapper.eq("category_id", categoryId);
List<Content> selectPage = mapper.selectPage(rowBounds, wrapper); Integer count = mapper.selectCount(wrapper); result.setTotal(count); result.setRows(selectPage);
return result; } } |
-
-
-
-
- 第七步:创建ContentController类
-
-
-
package cn.gzsxt.manager.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.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import cn.gzsxt.base.pojo.Content; import cn.gzsxt.base.vo.EUDataGridResult; import cn.gzsxt.base.vo.EgoResult; import cn.gzsxt.manager.service.ContentService; @Controller @RequestMapping("/content") public class ContentController {
@Autowired private ContentService service;
@RequestMapping(value="/query/list") @ResponseBody public EUDataGridResult selectByCatIdAndPage(Long categoryId,Integer page,Integer rows){ EUDataGridResult result = service.listByCatIdAndPage(categoryId, page, rows); return result; } } |
-
-
-
-
- 第八步:测试
-
-
-
(1)重新编译ego-manager工程。(clean、install)
(2)重新启动ego-manager。
(3)查看内容列表。成功!!!
-
-
-
- 第二部分:新增内容
- 第一步:前端js实现
- 第二部分:新增内容
-
-
-
-
-
-
- 第二步:确定代码结构
-
-
-
Controller | 接收表单数据,响应保存结果 |
Service | 保存逻辑实现 |
Mapper | 逆向工程生成 |
-
-
-
-
- 第三步:确定请求响应格式
-
-
-
请求路径 | /content/save |
请求方式 | POST |
请求参数 | Content类 |
响应格式 | {status:200} (EgoResult类型) |
-
-
-
-
- 第四步:修改ContentService接口及其实现类,新增save方法
-
-
-
@Override public EgoResult addContent(Content content) throws Exception { //把图片信息保存至数据库 content.setCreated(new Date()); content.setUpdated(new Date()); //把内容信息添加到数据库 mapper.insert(content); return EgoResult.ok(); } |
-
-
-
-
- 第五步:修改ContentController类,定义save接口
-
-
-
@RequestMapping("/save") @ResponseBody public EgoResult addContent(Content content) throws Exception { EgoResult result = service.addContent(content); return result; } |
-
-
-
- 第三部分:更新内容
- 第一步:前端js实现
- 第三部分:更新内容
-
-
-
-
-
-
- 第二步:确定请求响应格式
-
-
-
请求路径 | /content/edit |
请求方式 | POST |
请求参数 | Content类 |
响应格式 | {status:200} (EgoResult类型) |
-
-
-
-
- 第三步:修改ContentService接口及其实现类,新增update方法
-
-
-
@Override public EgoResult update(Content content) { mapper.updateById(content); return EgoResult.ok(); } |
-
-
-
-
- 第四步:修改ContentController类,新增update接口
-
-
-
@RequestMapping("/edit") @ResponseBody public EgoResult update(Content Content){ EgoResult result = service.update(Content); return result; } |
-
-
-
- 第四部分:删除内容
- 第一步:前端js实现
- 第四部分:删除内容
-
-
获取所有要删除的内容的id,封装到数组中。
-
-
-
-
- 第二步:确定请求响应格式
-
-
-
请求路径 | /content/delete |
请求方式 | POST |
请求参数 | Ids[]:{1,2,3} 数组类型 |
响应格式 | {status:200} (EgoResult类型) |
-
-
-
-
- 第三步:修改ContentService接口及其实现类,新增delete方法
-
-
-
@Override public EgoResult delete(Integer[] ids) { List<Integer> idss = Arrays.asList(ids); mapper.deleteBatchIds(idss); return EgoResult.ok(); } |
-
-
-
-
- 第五步:修改ContentController类,新增delete接口
-
-
-
@RequestMapping("/delete") @ResponseBody public EgoResult delete(Integer[] ids){ EgoResult result = service.delete(ids); return result; } |
- 首页大广告实现
- 需求
访问门户系统首页,在大广位区域展示大广告位对应的内容。
-
- 实现流程
(1)、在CMS系统中维护大广告位的内容。
(2)、在REST系统中查询大广告位的内容列表,以接口的形式对外提供服务。
(3)、在portal门户系统中远程访问REST系统。
-
- 第一部分:REST系统接口实现
需求:
根据内容分类id,查询tb_content表,获得大广告位内容列表。
-
-
- 第一步:确定代码结构
-
Controller | 定义接口规则(请求路径、请求方式、参数、响应值类型) |
Service | 定义查询逻辑 |
Mapper | 查询数据库 |
-
-
- 第二步:定义接口规则
-
请求路径 | /rest/content/category/{cid} |
请求方式 | GET |
请求参数 | /{cid} 路径变量 |
响应类型 | EgoResult |
示例 | demo |
-
-
- 第三步:创建ContentService接口及其实现类
-
package cn.gzsxt.rest.service.impl;
import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import cn.gzsxt.base.mapper.ContentMapper; import cn.gzsxt.base.pojo.Content; import cn.gzsxt.base.utils.JsonUtils; import cn.gzsxt.rest.service.ContentService;
@Service public class ContentServiceImpl implements ContentService{
@Autowired private ContentMapper mapper;
@Override public EgoResult getContentByCatId(Long catId) {
Map<String, Object> columnMap = new HashMap<>(); columnMap.put("category_id", catId); List<Content> list = mapper.selectByMap(columnMap);
return EgoResult.ok(list); } } |
-
-
- 第四步:创建ContentController类
-
@RestController @RequestMapping("/content") public class ContentController {
@Autowired private ContentService contentService;
@RequestMapping("/category/{cid}") public EgoResult getContentList(@PathVariable Long cid) { EgoResult result = contentService.getContentByCatId(cid); return result; } } |
-
- 第二部分:远程接口调用方式HttpClient
问题:现在我们已经开发好了接口了,那该如何调用这个接口呢?
答:使用Httpclient客户端。
-
-
- Httpclient简介
- 什么是httpclient
- Httpclient简介
-
HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)
-
-
-
- httpclient作用
-
-
在java代码中,发送Http请求。通常用来实现远程接口调用。
-
-
- HttpClient测试
-
说明:在ego-base中测试
在ego-base工程中添加httpclient的pom依赖。
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> |
-
-
-
- 执行GET请求
-
-
public static void doGet(){ // 创建Httpclient对象 CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建http GET请求 HttpGet httpGet = new HttpGet("http://www.oschina.net/");
CloseableHttpResponse response = null; try { // 执行请求 response = httpclient.execute(httpGet); System.out.println(response.getStatusLine()); // 判断返回状态是否为200 if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "UTF-8"); System.out.println("内容长度:" + content.length()); } }catch(Exception e){ e.printStackTrace();
} finally { if (response != null) { try { response.close(); } catch (IOException e) { e.printStackTrace(); } } try { httpclient.close(); } catch (IOException e) { e.printStackTrace(); } } |
-
-
-
- 执行GET带参数
-
-
public static void doGetParam(){ // 创建Httpclient对象 CloseableHttpClient httpclient = HttpClients.createDefault(); CloseableHttpResponse response = null; try {
// 定义请求的参数 URI uri = new URIBuilder("http://www.baidu.com/s").setParameter("wd", "数据库").build();
System.out.println(uri);
// 创建http GET请求 HttpGet httpGet = new HttpGet(uri);
// 执行请求 response = httpclient.execute(httpGet); // 判断返回状态是否为200 if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "UTF-8"); System.out.println(content); } }catch(Exception e){ e.printStackTrace();
}finally { if (response != null) { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { httpclient.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
-
-
-
- 执行post请求
-
-
public static void doPost(){ // 创建Httpclient对象 CloseableHttpClient httpclient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();
// 创建http POST请求 HttpPost httpPost = new HttpPost("http://www.oschina.net/");
CloseableHttpResponse response = null; try { // 执行请求 response = httpclient.execute(httpPost); System.out.println(response.getStatusLine()); // 判断返回状态是否为200 if (response.getStatusLine().getStatusCode() == 200) { String content = EntityUtils.toString(response.getEntity(), "UTF-8"); System.out.println(content); } }catch(Exception e){ e.printStackTrace();
}finally { if (response != null) { try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { httpclient.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
-
-
-
- 执行post带参数
-
-
public static void doPostParam() throws Exception{ // 创建Httpclient对象 CloseableHttpClient httpclient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();
// 创建http POST请求 HttpPost httpPost = new HttpPost("http://www.oschina.net/search");
// 设置2个post参数,一个是scope、一个是q List<NameValuePair> parameters = new ArrayList<NameValuePair>(); parameters.add(new BasicNameValuePair("scope", "project")); parameters.add(new BasicNameValuePair("q", "java")); // 构造一个form表单式的实体 UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters); // 将请求实体设置到httpPost对象中 httpPost.setEntity(formEntity);
CloseableHttpResponse response = null; try { // 执行请求 response = httpclient.execute(httpPost); System.out.println(response.getStatusLine()); // 判断返回状态是否为200 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(); } } |
-
-
- httpclient常见问题及解决方案
- 请求参数乱码
- httpclient常见问题及解决方案
-
设置请求的编码格式:
obj.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8"); |
-
-
-
- 响应HTTP/1.1 403 Forbidden
-
-
原因:网站设置了反爬虫机制,禁止非法访问。
解决方案:伪装浏览器。
obj.addHeader("User-Agent"," Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537. 36 (KHTML, like Gecko) Chrome/31.0.1650.63")
|
-
-
- 封装通用工具类HttpClientUtils
-
public class HttpClientUtils {
public static String doGet(String url,Map<String, String> params){
//获取httpclient客户端 CloseableHttpClient httpclient = HttpClients.createDefault();
String resultString = "";
CloseableHttpResponse response = null;
try { URIBuilder builder = new URIBuilder(url);
if(null!=params){ for (String key:params.keySet()) { builder.setParameter(key, params.get(key)); } }
HttpGet get = new HttpGet(builder.build());
response = httpclient.execute(get);
System.out.println(response.getStatusLine());
if(200==response.getStatusLine().getStatusCode()){ HttpEntity entity = response.getEntity(); resultString = EntityUtils.toString(entity, "utf-8"); }
} catch (Exception e) {
e.printStackTrace(); } finally { if(null!=response){ try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(null!=httpclient){ try { httpclient.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
return resultString; }
public static String doGet(String url){ return doGet(url, null); }
public static String doPost(String url,Map<String,String> params){ /** * 在4.0及以上httpclient版本中,post需要指定重定向的策略,如果不指定则按默认的重定向策略。 * * 获取httpclient客户端 */ CloseableHttpClient httpclient = HttpClientBuilder.create().setRedirectStrategy( new LaxRedirectStrategy()).build();
String resultString = "";
CloseableHttpResponse response = null;
try {
HttpPost post = new HttpPost(url);
List<NameValuePair> paramaters = new ArrayList<>();
if(null!=params){ for (String key : params.keySet()) { paramaters.add(new BasicNameValuePair(key,params.get(key))); }
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity (paramaters);
post.setEntity(formEntity); }
/** * HTTP/1.1 403 Forbidden * 原因: * 有些网站,设置了反爬虫机制 * 解决的办法: * 设置请求头,伪装浏览器 */ post.addHeader("user-agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
response = httpclient.execute(post);
System.out.println(response.getStatusLine());
if(200==response.getStatusLine().getStatusCode()){ HttpEntity entity = response.getEntity(); resultString = EntityUtils.toString(entity, "utf-8"); }
} catch (Exception e) {
e.printStackTrace(); } finally { if(null!=response){ try { response.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(null!=httpclient){ try { httpclient.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
return resultString; }
public static String doPost(String url){ return doPost(url, null); } } |
-
- 第三部分:portal系统实现
通过httpclient,远程调用REST接口,获取大广告位内容列表,放到作用域中,返回给页面。
-
-
- 第一步:前端js实现
-
说明:大广告位内容列表,是在视图中渲染出来的。
-
-
- 第二步:确定代码结构
-
Controller | 将数据模型放到作用域,渲染视图 |
Service | 通过HttpClient远程调用REST接口 |
-
-
- 第三步:创建大广告位ADItem类
-
package cn.gzsxt.portal.pojo;
/** * 大广告位数据显示格式 * @author ccnulyq * */ public class ADItem {
/** * {"srcB":"http://image.ego.com/images/2015/03/03/2015030304360302109345.jpg", * "height":240, * "alt":"", * "width":670, * "src":"http://192.168.23.4/images/1541214436730.jpg", * "widthB":550, * "href":"http://sale.jd.com/act/e0FMkuDhJz35CNt.html?cpdad=1DLSUE"," * heightB":240 * */
private String srcB;
private int height= 240;
private String alt;
private int width=670;
private String src;
private int widthB = 550;
private String href;
private int heightB=240; public ADItem() { super(); } // 补全get、set方法 } |
-
-
- 第四步:创建resourse.properties配置文件
-
(1)在src目录下创建,配置rest系统基本信息。
REST_BASE_URL=http://localhost:8081/rest REST_INDEX_AD_URL=/content/category/89 |
(2)修改spring-mvc.xml文件,加载该配置文件
<context:property-placeholder file-encoding="utf-8" location="classpath:resourse.properties"/> |
-
-
- 第五步:创建ContentService接口及其实现类
-
@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 getAdItemList() throws Exception { //调用服务层的服务查询打广告位的数据 String result = HttpClientUtils.doGet(REST_BASE_URL + REST_INDEX_AD_URL); //把json数据转换成对象 EgoResult egoResult = EgoResult.formatToList(result, TbContent.class); List<ADItem> itemList = new ArrayList<>(); if (egoResult.getStatus() == 200 ) { List<Content> contentList = (List<Content>) egoResult.getData(); for (Content content : contentList) { ADItem item = new ADItem(); item.setSrc(content.getPic()); item.setSrcB(content.getPic2()); item.setAlt(content.getTitleDesc()); item.setHref(content.getUrl()); itemList.add(item); } } return JsonUtils.objectToJson(itemList); } } |
--JsonUtils
public class JsonUtils {
// 定义jackson对象 private static final ObjectMapper MAPPER = new ObjectMapper();
/** * 将对象转换成json字符串。 * <p>Title: pojoToJson</p> * <p>Description: </p> * @param data * @return */ public static String objectToJson(Object data) { try { String string = MAPPER.writeValueAsString(data); return string; } catch (JsonProcessingException e) { e.printStackTrace(); } return null; }
/** * 将json结果集转化为对象 * * @param jsonData json数据 * @param clazz 对象中的object类型 * @return */ public static <T> T jsonToPojo(String jsonData, Class<T> beanType) { try { T t = MAPPER.readValue(jsonData, beanType); return t; } catch (Exception e) { e.printStackTrace(); } return null; }
/** * 将json数据转换成pojo对象list * <p>Title: jsonToList</p> * <p>Description: </p> * @param jsonData * @param beanType * @return */ public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) { JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType); try { List<T> list = MAPPER.readValue(jsonData, javaType); return list; } catch (Exception e) { e.printStackTrace(); }
return null; } }
|
3.5.5、第六步:修改PageController类
首先大广告位的内容,是在访问首页的时候加载的。因此,我们可以在showIndex方法中调用service。
@Controller public class PageController { @Autowired private ADService adService;
@RequestMapping("/index") public String showIndex(Model model) throws Exception { String adResult = adService.getAdItemList(); model.addAttribute("ads", adResult); return "index"; } } |
-
-
- 第六步:测试
-
(1)重启rest、portal工程
(2)访问门户系统首页。