课堂笔记 - 电商项目开发笔记-03

 

易购商城

第三天

 

 

 

 

  

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. 课程计划

(1)搭建前台系统。

(2)完成首页导航菜单。(学习jsonp)

(3)完成CMS内容管理系统。

(4)完成首页大广告位投放。(学习Httpclient)

 

  1. 搭建前台系统
    1. 前台系统架构

在互联网系统开发当中,我们一般都是采用了分层的方式来架构系统,即:

(1)门户层(门户系统):网站的入口

i、渲染视图,提供用户访问的页面。

ii、不查询数据库,数据来自对远程服务(接口)的调用。

(2)服务层:基于restful,以接口的形式对外提供公共的服务。

i、连接数据库,返回json格式的数据。

 

      1. 分层架构的好处

(1)、有利于系统的维护和拓展。

(2)、有利于SOA服务治理的基础。

    1. 搭建服务层系统
      1. 系统简介

基于RESTful实现。以接口的形式,对外提供公共的服务。(比如购物车、导航菜单、搜索、订单等等)

RESTful是一种接口设计理念,即:

(1)不同的请求方式,对应不同的业务类型:

       GET   :查询

       POST  :添加

       PUT   :更新

       DELETE: 删除

(2)返回json格式数据。

 

      1. 技术选择

核心框架:Spring+SpringMVC+Mybatis-plus

数 据 库:MySQL

前端框架:无

 

      1. 配置步骤

思路:(1)创建项目,导入jar依赖。

         (2)整合SSM框架。

 

        1. 第一步:创建maven项目(war)模型

注意:(1)项目继承ego-project。

      (2)使用maven module创建项目

 

        1. 第二步:导入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、springmvcmybatis相关依赖 -->

<!-- 导入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>

 

        1. 第三步:创建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>

 

        1. 第四步:整合SSM框架

整合中所需要的配置文件,均可从ego-manager工程中拷贝,修改局部的配置即可。

          1. 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>

 

          1. 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>

 

 

        1. 第五步:整合测试

在这里我们使用静态数据(category.json),来模拟导航菜单接口的实现。

 

(1)拷贝category.json文件到webapp目录下。

 

(2)更新项目、安装到本地仓库(updata、maven clean、maven install)

(3)启动项目

 

查看控制台,启动成功!!!

 

(4)浏览器访问,地址:http://localhost:8081/category.json整合成功!!!

 

    1. 搭建门户系统
      1. 系统简介

简单来说就是网站的入口,提供用户浏览、下单的操作页面。

门户系统不直接调用数据库,而是通过服务系统提供的接口获取数据。电商、互联网行业开发都是面向服务开发。

      1. 技术选择

核心框架:Spring+SpringMVC

数 据 库:无

前端技术:jquery、ajax、css+div、easyui等

 

      1. 配置步骤

思路:(1)创建项目

         (2)框架整合

 

        1. 第一步:创建maven项目(war模型)

注意:(1)继承ego-project工程

      (2)使用maven module创建子系统

 

        1. 第二步:导入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>

 

        1. 第三步:创建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>

 

        1. 第四步:导入jsp页面、静态资源

说明:(1)静态资源放在/webapp目录

         (2)jsp放到/WEB-INF/JSP目录下

 

        1. 第五步: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. 第六步:整合测试

需求:访问门户系统首页。

 

(1)创建PageController类

package cn.gzsxt.portal.controller;

 

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

 

@Controller

public class PageController {

 

@RequestMapping("/index")

public String showIndex(){

 

return "index";

}

}

 

(2)更新项目、安装到本地仓库。(update、clean、install)

(3)启动项目

 

(4)访问首页,地址:http://localhost:8082

 

前台系统搭建成功!!!

 

  1. 首页导航菜单实现

说明:首页导航菜单,是通过异步加载实现的。

好处:只有当展开导航菜单时,才会发送请求,从而节约cpu资源。

 

    1. 实现流程

 

需要解决的问题:

(1)在rest系统中发布接口,封装导航菜单成json格式数据。

(2)在portal系统中,远程请求接口(跨域请求)。

 

    1. 跨越请求
      1. 什么是跨域(两个不同系统之间的访问、调用)

(1)域名不同,即两个不同的应用。

 

(2)域名相同,但是端口不同,即同一个应用中的不同子系统。

 

      1. Ajax跨域请求的缺陷

在ego-rest系统使用静态数据,模拟Ajax的跨域问题。

 

        1. 第一步:在ego-rest中添加category.json文件。(已实现)
        2. 第二步:在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;

}

 

        1. 第三步测试Ajax跨越

(1)重启启动ego-portal系统,访问testJsonp.jsp

(2)点击按钮,发送异步请求

 

测试发现,Ajax跨越请求失败了

 

      1. 解决方案:jsonp跨域

在前面的测试中,我们发现Ajax跨越请求时,json数据被浏览器禁用了。

原因:浏览器禁止远程加载Json数据。(浏览器安全机制)

 

如何解决呢?

答:使用Jsonp方式。

 

        1. Jsonp原理

Jsonp实现的前提:

浏览器允许跨越加载同源数据。

即在JavaScript脚本中发送请求,就可以远程加载js格式数据。

 

请求原理:

(1)异步请求的时候,加上一个名为callback的回调函数

(2)在接口中,将返回的json格式数据,伪装成js脚本格式。

(3)得到js格式数据后,提取里面的json数据。

 

        1. 测试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. 首页导航菜单实现

思路:

(1)在rest工程中,开发接口,返回js格式数据。(参考category.json)

(2)在portal工程中,修改jsonp请求路径。请求rest接口。

 

      1. 第一部分:在rest工程中开发导航菜单接口
        1. 第一步:定义导航菜单POJO

导航菜单结构分析。(使用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)

 

        1. 第二步:创建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;

}

}

 

        1. 第三步创建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;

}

 

        1. 第四步:测试接口

在浏览器访问。

地址:http://localhost:8081/rest/item/all?callback=category.getDataService

 

      1. 第二部分在portal工程中调用导航菜单接口
        1. 第一步指定请求方式为jsonp

(1)修改lib-v1.js文件,指定导航菜单接口地址。

 

(2)修改lib-v1.js文件,指定请求方式为jsonp。

 

        1. 第二步:测试导航菜单

(1)重启portal工程

(2)访问首页,请求导航菜单

导航菜单开发成功!!!

  1. CMS系统
    1. 概念

CMS系统即为内容管理系统。(Content Management System)

 

所谓的内容,就是出现在网页中的图片、文字、链接等。CMS系统就是用来维护网页中的内容的,实现网页中的内容动态、可变。

比如广告位的投放,秒杀栏、排行榜实时更新等,都需要通过CMS系统来实现。

 

    1. CMS系统实现
      1. 思路

(1)、将网页中的内容分类

按照网页的特性分类,然后将每一类网页划分成一个一个独立的区域。

 

(2)在每一个内容分类下管理、维护各自的内容列表。

 

      1. 数据库表关系

CMS系统主要涉及两种表:

(1)内容分类表:tb_content_category(作用:定位)

(2)内容表:tb_content

 

表之间的对应关系为1-N

 

      1. 内容分类实现
        1. 需求

在后台管理页面,点击内容分类管理菜单,初始化内容分类树结构。该树结构可以添加、修改、删除节点。

 

        1. 思路

(1)初始化内容分类导航树。(这里使用easyui-tree)

(2)对异步树进行维护。(添加节点、删除节点、更新节点)

 

        1. 第一部分:初始化内容分类导航树
          1. 第一步:初始化easyui异步树插件

 

          1. 第二步:确定代码结构

Controller

表现层,负责交互、绑定参数、响应视图

Service

业务层,负责业务逻辑实现(封装树结构)

Mapper

持久层,逆向工程生成,不需要开发。

 

          1. 第三步:确定请求响应格式

请求路径

/content/category/list

请求方式

GET请求

请求参数

id=nodeId(首次加载生成一级目录时,默认id=0)

响应格式

List<EUTreeNode> (id,text,state:open|closed)

 

          1. 第四步:创建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();

}

// 补全getset方法

}

 

          1. 第五步:创建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>{

 

}

 

          1. 第六步:创建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;

}

}

 

          1. 第七步:创建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. 第八步:测试

(1)重新编译ego-manager工程。(clean、install)

(2)重新启动ego-manager。

(3)访问内容分类管理

 

        1. 第二部分:添加内容分类节点
          1. 第一步:前端js实现

 

          1. 第二步:确定代码结构

Controller

视图层,接收参数,将新增加的节点响应出去

Service

业务层,新增节点、更新父节点

Mapper

持久层,逆向工程生成,不需要开发。

 

          1. 第三步:确定请求响应格式

请求路径

/content/category/create

请求方式

POST

请求参数

parentId:node.parentId,   name:node.text

响应格式

{status:200,data:node}  (EgoResult类型)

 

          1. 第四步:修改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);

}

 

          1. 第五步:修改ContentCategoryController类,定义新增内容分类接口

@RequestMapping(value="/create",method=RequestMethod.POST)

@ResponseBody

public EgoResult create(Long parentId,String name){   

EgoResult result = catService.save(name, parentId);

 

return result;

}

 

          1. 第六步:测试

(1)重新编译ego-base工程。(clean、install)

(2)重新启动ego-manager。

(3)新增内容分类节点。

 

 

        1. 第三部分:更新内容分类
          1. 第一步:前端js实现

 

          1. 第二步:确定请求响应格式

请求路径

/content/category/updata

请求方式

POST

请求参数

id:node.id,   name:node.text

响应格式

{status:200,data:node}  (EgoResult类型)

 

          1. 第三步:修改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();

}

 

          1. 第四步:修改ContentController类,定义更新的接口

@RequestMapping(value="/update",method=RequestMethod.POST)

@ResponseBody

public EgoResult updateNode(Long id,String name){

EgoResult result = catService.updateNode(name, id);

return result;

}

 

          1. 第五步:测试

(1)重新编译ego-manager工程。(clean、install)

(2)重新启动ego-manager。

(3)更新内容分类节点。

 

        1. 第四部分:删除内容分类
          1. 第一步:前端js实现

 

          1. 第二步:确定请求响应格式

请求路径

/content/category/delete

请求方式

POST

请求参数

id:node.id,   parentId:node.parentId

响应格式

{status:200,data:node}  (EgoResult类型)

 

          1. 第三步:修改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();

}

 

          1. 第四步:修改ContentCategoryController类,定义delete接口

@RequestMapping(value="/delete",method=RequestMethod.POST)

@ResponseBody

public EgoResult deleteNode(Long id,Long parentId){

EgoResult result = catService.deleteNode(id, parentId);

return result;

}

      1. 内容管理实现
        1. 需求

根据内容分类id,查询数据库表tb_content,获取内容列表。

内容分类树使用easyui-tree组件,内容列表使用easyui-datagrid组件。

 

        1. 思路

(1)实现内容列表查询。

(2)在内容分类节点下,维护内容列表。

 

        1. 第一部分:内容列表实现
          1. 第一步:加载easyui-datagrid插件

(1)初始化分类导航树(后台java已实现,见2.2.1.3.2章节)

 

(2)选中内容分类节点

 

(3)查询该节点下的内容列表

 

          1. 第二步:确定代码结构

Controller

获取分类ID,分页信息,响应列表数据

Service

分页查询逻辑

Mapper

逆向工程生成,不需要开发

 

          1. 第三步:确定请求响应结构

请求路径

/content/query/list

请求方式

GET

请求参数

{categoryId:0  ,  page:1  ,  rows:20}

响应格式

{total:20,rows:dataList}  (参见ego-base中的EUDataGridRestult类)

          1. 第四步:创建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();

}

 

// 补全getset方法

}

 

          1. 第五步:创建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>{

 

}

 

          1. 第六步:创建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;

}

}

 

          1. 第七步:创建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. 第八步测试

(1)重新编译ego-manager工程。(clean、install)

(2)重新启动ego-manager。

(3)查看内容列表。成功!!!

 

        1. 第二部分:新增内容
          1. 第一步:前端js实现

 

          1. 第二步:确定代码结构

Controller

接收表单数据,响应保存结果

Service

保存逻辑实现

Mapper

逆向工程生成

 

          1. 第三步:确定请求响应格式

请求路径

/content/save

请求方式

POST

请求参数

Content类

响应格式

{status:200}  (EgoResult类型)

 

          1. 第四步:修改ContentService接口及其实现类,新增save方法

@Override

public EgoResult addContent(Content content) throws Exception {

//把图片信息保存至数据库

content.setCreated(new Date());

content.setUpdated(new Date());

//把内容信息添加到数据库

mapper.insert(content);

return EgoResult.ok();

}

 

          1. 第五步:修改ContentController类,定义save接口

@RequestMapping("/save")

@ResponseBody

public EgoResult addContent(Content content) throws Exception {

EgoResult result = service.addContent(content);

return result;

}

 

        1. 第三部分:更新内容
          1. 第一步:前端js实现

 

          1. 第二步:确定请求响应格式

请求路径

/content/edit

请求方式

POST

请求参数

Content类 

响应格式

{status:200}  (EgoResult类型)

 

          1. 第三步:修改ContentService接口及其实现类,新增update方法

@Override

public EgoResult update(Content content) {

mapper.updateById(content);

return EgoResult.ok();

}

 

          1. 第四步:修改ContentController类,新增update接口

@RequestMapping("/edit")

@ResponseBody

public EgoResult update(Content Content){

EgoResult result = service.update(Content);

return result;

}

 

        1. 第四部分:删除内容
          1. 第一步前端js实现

 

获取所有要删除的内容的id,封装到数组中。

 

          1. 第二步:确定请求响应格式

请求路径

/content/delete

请求方式

POST

请求参数

Ids[]:{1,2,3}  数组类型

响应格式

{status:200}  (EgoResult类型)

 

          1. 第三步:修改ContentService接口及其实现类,新增delete方法

@Override

public EgoResult delete(Integer[] ids) {

List<Integer> idss = Arrays.asList(ids);

        mapper.deleteBatchIds(idss);

return EgoResult.ok();

}

 

          1. 第五步:修改ContentController类,新增delete接口

@RequestMapping("/delete")

@ResponseBody

public EgoResult delete(Integer[] ids){

EgoResult result = service.delete(ids);

return result;

}

 

  1. 首页大广告实现
    1. 需求

访问门户系统首页,在大广位区域展示大广告位对应的内容。

    1. 实现流程

(1)、在CMS系统中维护大广告位的内容。

(2)、在REST系统中查询大广告位的内容列表,以接口的形式对外提供服务。

(3)、在portal门户系统中远程访问REST系统。

 

    1. 第一部分:REST系统接口实现

需求:

根据内容分类id,查询tb_content表,获得大广告位内容列表。

      1. 第一步:确定代码结构

Controller

定义接口规则(请求路径、请求方式、参数、响应值类型)

Service

定义查询逻辑

Mapper

查询数据库

 

      1. 第二步:定义接口规则

请求路径

/rest/content/category/{cid}

请求方式

GET

请求参数

/{cid}  路径变量

响应类型

EgoResult

示例

demo

 

      1. 第三步:创建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);

}

}

      1. 第四步:创建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;

}

}

 

    1. 第二部分:远程接口调用方式HttpClient

问题:现在我们已经开发好了接口了,那该如何调用这个接口呢?

答:使用Httpclient客户端。

 

      1. Httpclient简介
        1. 什么是httpclient

HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。实现了所有 HTTP 的方法(GET,POST,PUT,HEAD 等)

下载地址:http://hc.apache.org/

 

        1. httpclient作用

在java代码中,发送Http请求。通常用来实现远程接口调用。

      1. HttpClient测试

说明:在ego-base中测试

在ego-base工程中添加httpclient的pom依赖。

<dependency>

<groupId>org.apache.httpcomponents</groupId>

<artifactId>httpclient</artifactId>

</dependency>

 

        1. 执行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();

}

        }

 

        1. 执行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();

}

        }

}

 

        1. 执行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();

}

        }

    }

 

        1. 执行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();

        }

}

 

      1. httpclient常见问题及解决方案
        1. 请求参数乱码

设置请求的编码格式:

obj.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");

 

        1. 响应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")

 

 

      1. 封装通用工具类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);

}

 }

 

    1. 第三部分:portal系统实现

通过httpclient,远程调用REST接口,获取大广告位内容列表,放到作用域中,返回给页面。

 

      1. 第一步:前端js实现

说明:大广告位内容列表,是在视图中渲染出来的。

 

      1. 第二步:确定代码结构

Controller

将数据模型放到作用域,渲染视图

Service

通过HttpClient远程调用REST接口

 

      1. 第三步:创建大广告位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();

}

// 补全getset方法

}

 

      1. 第四步:创建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"/>

 

      1. 第五步:创建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. 第六步测试

(1)重启rest、portal工程

(2)访问门户系统首页。

 

转载于:https://my.oschina.net/u/4118325/blog/3080848

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值