个人网站的作用/seo免费推广
1.实现商品详情页
1.1 详情页的基本商品信息
1.1.1 在后台系统中提供查询商品接口
首页中查询商品,要获取商品详情数据,肯定要查询后台的接口,因此我们需要在后台管理系统中添加查询商品详情的接口:
定义Controller
- 请求路径:manage.taotao.com/rest/api/item/{itemId}
- 请求参数:商品id
- 返回值:某个商品的json数据(因为我们这边采用httpClient,而非jsonp,所以在后台代码中不用判断callback)
查询商品:
@RequestMapping("api/item")
@Controller
public class ApiItemController {@Autowiredprivate ItemService itemService;@RequestMapping(value="{itemId}", method = RequestMethod.GET)public ResponseEntity<Item> queryItemById(@PathVariable("itemId")Long itemId){Item item = this.itemService.queryById(itemId);System.out.println(item);if(item != null){return ResponseEntity.ok(item);}return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);}
}
查询商品描述:
数据库中有一个ID为42的商品,我们查询试试:
1.1.2 在后台系统中提供查询商品接口
(1)详情页地址分析:
你会发现其地址中的html其实是商品的id 信息。我们模仿这种方式,我们的路径应该是:
http://www.taotao.com/item/{itemId}.html
这样以来,我们可以通过路径来获取商品id,完成对商品信息的查询!
(2)定义controller
- 请求路径: / item/{itemId}
- 请求参数: {itemId}
- 返回值: 需要跳转到item.jsp页面,并加载数据。因此返回ModelAndView
商品详情页已经有写好的JSP页面了:
因此我们需要把数据封装到ModelAndView中,返回到这个JSP视图,然后进行渲染即可。
编写Controller:此处我们用到了后台系统中的pojo,所以我们需要将后面的pojo模块maven install,而后在前台系统中maven add dependency(引入依赖),这里也体现了maven项目的优势
(3)编写service
通过httpClient来访问后台接口
(4)测试
在浏览器中输入地址:http://www.taotao.com/item/42.html
访问路径,发现页面没有内容:
后台出错了:
页面中解析商品的图片使用到了images属性:
可以看出这里的images是一个数组形式数据。而我们的Item类没有这个属性,只有image属性,是把图片地址以,拼接的字符串:
现在思路有2个:
1)修改taotao-manage中的 Item类,增加getImages方法
2)我们在前台系统新增一个自己的Item类。
选哪个?
因为后台系统不仅仅提供服务给前台,可能还有其它系统,因此我们不能随意修改后台系统的代码。这里选择方案2
(5)定义VO对象
我们在前台系统定义用于页面展示的对象,称为VO对象(视图对象)。
然后修改Controller和Service中的Item类型为ItemVO,重启后再次测试:
1.2 详情页的商品描述信息
1.2.1 后台系统中提供查询商品描述的接口
(1)编写API的controller
1.2.2 前台系统中实现商品详情页的具体描述
在item.jsp中
因此,我们只要在模型中添加商品描述信息:itemDesc即可:
编写Service
2.给商品详情页添加缓存
商品页详情,查询非常频繁,但几乎不会修改.这样的页面我们一般都会进行优化处理,有两种手段
- 加缓存
- 做页面的静态化
做页面的静态化:
把需要动态加载的JSP变成HTML页面,然后放到nginx服务器,以后所有的请求都直接由nginx处理,不再经过Tomcat。
问题1:如何把jsp变成HTML?
自己通过http请求,访问自己的页面,你就能获取页面的HTML代码,然后把它写入一个本地.html文件,然后把文件放到nginx服务器。
问题2:如何保证页面的内容跟数据库一致?
需要不断更新静态页面,两种方式:
- 1)定时任务,过一段时间自动去重新查询,生成HTML
- 2)每当后台对商品进行 增、删、改操作,都重新生成html
2.1 需求分析
(1)为什么要添加缓存
一个接口是否需要添加缓存,依据有哪些?
- (1)数据查询非常频繁
- (2)数据更新频率低下
商品详情页数据查询比较频繁,而且商品的详情变化的频率也是比较低的。为了提高页面加载的速度,我们需要添加缓存。
(2)在哪里添加缓存
是前台系统还是后台系统?
这部分功能有两部分组成:后台系统对外提供查询接口,前台系统通过HttpClient访问后台系统,然后封装数据到模型。
两个系统相互独立,各司其职,因此都应该加缓存
2.2 将缓存功能抽取到taotao-common
因为前台和后台甚至以后的某些系统也会用到Redis功能,因此我们考虑把RedisService抽取到taotao-common中。
(1)在common中添加依赖
需要导入Jedis的依赖,同时因为要使用@Service注解,还需要Spring依赖。
<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>1.6.1.RELEASE</version>
</dependency>
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.7.3</version>
</dependency>
(2)移动RedisService到common中:
设置注入策略
要注意,RedisService中需要注入StringRedisTemplate,而并不是每一个依赖common的工程都需要Redis功能,那么这些工程就不会配置StringRedisTemplate。
但是如果不配置,注入就会失败。
这里设置required = false 。这样如果没有在spring中配置StringRedisTemplate,就不会注入,也不会报错。
方法一:移除后台系统的RedisService和配置
这样后台系统就不需要写RedisService了。移除这个类。同时我们可以选择将后台的redis配置移植到工具类中
此时applicationContext_redis.xml被我们移植到taotao-common.jar中
当我们启动manage.taotao.com项目时,初始化spring容器时,虽然写了classpath:spring/applicationContext*.xml,但是这个classpath默认是自己项目下,我们当前的maven工程,都是将所有配置写在web模块中,而此时却要读取依赖的jar包中的配置
那么如何才能读取依赖的jar包中的配置:classpath*
现在可以读取到applicationContext-redis.xml了,但是在这个配置中引用了redis.property文件,这怎么办?有些系统可能需要RedisServcie这个类,可以在自己项目中配置redis.property,但是其他系统依赖taotao-common,可能用不到redis.property,你不应该让他们也配置,所以我们想到用默认值
那么此时肯定可以注入StringRedisTemplate,所以可以删除required=false
切记:一定要把common重新install
2.3 前台系统查询商品添加缓存
(1)将配置文件复制到前台
如果采用了上面的classpath*方法,这里就不用导入applicationContext-redis.xml了
将applicationContext-redis.xml和redis.properties都复制到前台系统
在Spring配置中,引入redis.properties文件:
(2)在ItemService中添加缓存逻辑
3.单点登录系统
3.1 以前的登录有什么问题?
传统登录问题:
之前实现的登录和注册是在同一个tomcat内部完成。我们现在的系统架构是每一个系统都是由一个团队进行维护,每个系统都是单独部署运行一个单独的tomcat,所以,不能将用户的登录信息保存到session中(多个tomcat的session是不能共享的),所以我们需要一个单独的系统来维护用户的登录信息。
如何解决?
解决的关键就在于如何实现多个Tomcat之间的数据共享,Session是无法完成这一点的,因此我们需要用其它东西来代替Session的功能。
要代替Session,需要具备怎样的特点?
1)内存中保存,速度快
2)数据具有时效性
而这些特性Redis都具备,因此我们的解决方案就是使用Redis来代替Session。在一个独立系统中完成登录注册的逻辑,并完成用户登录时数据保存到Redis中。这样的一个系统就是单点登录系统(SSO)
3.2 登录流程图
这套流程只能运行在单Tomcat中,因为Session无法共享
现在的登录流程
其中关键的部分,就是用token来代替sessionID,模拟的session的功能
cookie的跨域问题:
- cookie的domain属性决定了cookie是否会被携带。如果请求的url路径,跟domain属性不一致,就不会携带cookie
- domain: jd.com -> www.jd.com paimai.jd.com
复杂的单点登录:
如果cookie被禁用怎么办?
- 1)提醒用户,你的cookie被禁用。然后给一个help页面,教如何设置。
- 2)在url地址后面拼接cookie参数
那么如果cookie被盗用怎么办?
- 1)如何防止被盗用?很难
- 2)在cookie加入认证信息,让cookie可以识别身份。(比如在cookie中保存用户设备信息)
- a)我们在cookie中加入识别信息,如果黑客模拟cookie?我们可以在cookie写随机数
- b)如何避免用户解读你的cookie。非对称加密
- 3)Https协议
4.创建单点登录系统
4.1 创建工程
4.2 添加依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.taotao.parent</groupId><artifactId>taotao-parent</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>com.taotao.sso</groupId><artifactId>taotao-sso</artifactId><version>1.0.0-SNAPSHOT</version><packaging>war</packaging><dependencies><dependency><groupId>com.taotao.common</groupId><artifactId>taotao-common</artifactId><version>1.0.0-SNAPSHOT</version></dependency><!-- 单元测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId></dependency><!-- Mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId></dependency><!-- 通用Mapper --><dependency><groupId>com.github.abel533</groupId><artifactId>mapper</artifactId></dependency><!-- MySql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></dependency><!-- Jackson Json处理工具包 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId></dependency><!-- 连接池 --><dependency><groupId>com.jolbox</groupId><artifactId>bonecp-spring</artifactId></dependency><!-- JSP相关 --><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><scope>provided</scope></dependency><!-- Apache工具组件 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-io</artifactId></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.6</version></dependency></dependencies><build><plugins><!-- 配置Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><configuration><port>8083</port><path>/</path></configuration></plugin></plugins></build>
</project>
4.3 编写配置
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"id="WebApp_ID" version="2.5"><display-name>taotao-sso</display-name><!-- 指定Spring配置文件的位置 --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/applicationContext*.xml</param-value></context-param><!--Spring的ApplicationContext 载入 --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 编码过滤器,以UTF8编码 ,解决POST乱码问题--><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF8</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- 配置SpringMVC框架入口 --><servlet><servlet-name>taotao-sso</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定SpringMVC配置文件的位置 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/taotao-sso-servlet.xml</param-value></init-param><!-- 设置随着Tomcat启动而加载 --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>taotao-sso</servlet-name><url-pattern>*.html</url-pattern></servlet-mapping><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list></web-app>
SSM相关配置
可以直接去taotao-manage-web中复制,然后去除一些不必要的部分即可
4.4 静态资源
从前台系统中拷贝以下静态页面:
4.5 编写Controller实现页面跳转
4.6 启动并测试
添加Nginx配置,代理 sso.taotao.com
注意reload
访问效果:
所有的CSS和JS加载都失败了:
5 解决静态资源共享问题
5.1 问题分析及解决方案
静态资源访问不到的原因是什么?
因为我们的页面是从taotao-web拷贝而来,所有的JS和CSS样式都是在taotao-web系统中。而页面访问CSS和JS是用的相对路径,肯定会在当前项目中找,自然找不到。
方案:
-
1、将taotao-web中的js和css拷贝到taotao-sso中
a)好处:简单、方便
b)缺点:重复、对用户而言需要重复加载
c)需要经过Tomcat加载JS,请求压力大 -
2、将taotao-sso中的引用指向 www.taotao.com
a)好处:对用户而言只需要加载一次即可
b)缺点:修改页面
c)需要经过Tomcat加载JS,请求压力大
方案三:
将静态资源统一放在Nginx服务器,然后通过nginx访问静态资源,JS、CSS、Image。不再经过Tomcat
优势:
1)用户只需加载一次
2)减少了Tomcat压力
缺点:也需要修改页面路径
5.2 具体步骤
(1)在虚拟机创建静态资源文件夹
(2)配置Nginx,代理静态资源域名,指向本地的静态资源文件
指向本地root用户下/taotao/static目录下
为什么要配置新的静态资源域名?static.taotao.com,跟cookie有关
使用新的域名,客户端请求JS和CSS等静态资源时,就不会带上其它域名中的cookie,提高效率。
(3)修改页面的资源路径
这里只截取一部分
此时我们请求的静态资源路径就是 static.taotao.com,nginx服务器解析后到root 用户下/taotao/static中去获取对应资源
测试:
上面修改页面路径的时候,每个页面都要单独注入静态页面地址,不利于后续的开发维护。
有没有办法可以把静态资源路径放到配置文件中,每个页面中都可以读取到?
思路:
1)在web.xml中配置contextParam
配置在contextParam标签中的值,是保存在servletContext中,全局的
2)在jsp页面使用${initParam.xxx}引用