jt-web服务器

京淘分布式架构-jt-web服务器

项目架构图设计
在这里插入图片描述

JT-WEB项目构建

在这里插入图片描述

选择打包类型
在这里插入图片描述

添加继承依赖插件

# parent是默认存在的表示继承关系,继承jt父级工程
<parent>
    <groupId>com.jt</groupId>
    <artifactId>jt</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  
  #我们jt-web服务器也要依赖于jt-common,因为里面有公共的api
  <dependencies>
		<dependency>
			<groupId>com.jt</groupId>
			<artifactId>jt-common</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
	</dependencies>


	<!--3.添加插件 -->
	<!--负责项目打包 更新 maven操作相关的配置 必须添加 -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

导入静态资源文件

说明:将资料src导入jt-web服务器
在这里插入图片描述

编辑主启动类

在这里插入图片描述

在这里插入图片描述

项目启动测试

在这里插入图片描述

配置nginx实现反向代理

在这里插入图片描述

修改nginx配置文件

在这里插入图片描述

效果展现

在这里插入图片描述

页面通用跳转

说明: 浏览器通过网址查询静态页面时,需要在后端服务器中准备固定的页面.才能正确的访问

在这里插入图片描述

疑问: 京东家的商品有上千万.如果采用上述的方式进行访问,则必须准备上千万的.html页面,才能实现商品的展现. 这样的方式不合理.

正确的方式: 应该准备一个公共的页面,之后根据商品的ID进行查询.之后在同一个页面中展现不同的商品信息即可.

开启后缀类型匹配

问题:如何能够拦截.html为结尾的请求,之后实现由mvc通过视图解析器实现程序的页面跳转

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这样子写访问确实没有问题,但是感觉这么写有点怪!我们路径很少这么写.html结尾的,所以我们要优化一下。

解决方案: 添加配置类

在这里插入图片描述

编辑UserController

说明:编辑userController实现用户注册/登录页面跳转

@RequestMapping("/user")
@Controller  //因为这里是页面的跳转,必定经过视图解析器
public class UserController {
		
	/**
	 * 实现用户页面跳转
	 * http://www.jt.com/user/register.html    后端页面register.jsp
	 * http://www.jt.com/user/login.html	        后端页面login.jsp
	 * 重点:为了实现业务功能,拦截.html结尾的请求
	 */
	
	//因为前端数据发起的ajax请求是http://www.jt.com/user/register.html,但是我们开启了后缀类型匹配则可实现页面跳转
	@RequestMapping("/register")
	public String register() {
		
		//经过视图解析器,跳转指定的页面中
		return "register";
	}
	
	
	@RequestMapping("/login")
	public String login() {
		
		//经过视图解析器,跳转指定的页面中
		return "login";
	}
}

为什么页面以.html结尾

说明: .html结尾的请求更容易被搜索引擎收录.增强网站的曝光率.

倒排索引: 根据关键字检索文件的位置
搜索引擎工作原理:
在这里插入图片描述

在这里插入图片描述

根据数据库的信息,生成索引记录。国内主流的分词器ik分词器。它会根据中国人特有的语意,把我们的数据进行划分。比方说:
我们的索引表里面根据 '三国’两个关键字去搜索,在页面显示的第一个数据就是我们的三国志丶再到三国杀…等等。

百度里面有一些竞价排名的相关机制,比方说我三国演义这个关键字花钱了,我们只需在索引表里根据三国关键字搜索的位置排名靠前就可以了。

问题:为什么我们要以html结尾呢?为什么搜索引擎要收录html结尾的数据呢,而不收录我们jsp这样的动态页面呢???
原因:假设三国志这间网站公司经营不善了做不下去了,然后里面的内容换了都是淫秽的信息,为了增加网站的访问量。如果搜索引擎收录了的是类似于jsp这样的动态页面,那么该三国志网站内的数据可以随意更换,因为是动态的数据,这样就会导致我们检索的数据和真实的数据严重的不一致。
所以后来百度就规定说了,以后我们收录的就是以.html结尾的静态页面。静态页面一样可以改数据,但是你的是动态页面百度不收录。因为如果收录动态页面的数据,百度也有风险,谁知道你网站里面的真实数据是怎么样的呢!

伪静态 --假的,是用来骗搜索引擎的

伪静态是相对真实静态来讲的,通常我们为了增强搜索引擎的友好面,都将文章内容生成静态页面,但是有的朋友为了实时的显示一些信息。或者还想运用动态脚本解决一些问题。不能用静态的方式来展示网站内容。但是这就损失了对搜索引擎的友好面。怎么样在两者之间找个中间方法呢,这就产生了伪静态技术。伪静态技术是指展示出来的是以html一类的静态页面形式,但其实是用ASP一类的动态脚本来处理的。
总结: 以.html为结尾的展现动态页面的技术称之为伪静态.

创建jt-sso

为什么要创建jt-sso服务器?因为当前我们用户在jt-web服务器的时候点击了注册,然而我们jt-web服务器是没有连接数据源的也就是没连接数据库的。那么怎么确定我们用户注册的时候这个用户名或者其它的相关信息是否已经被注册过了呢?所以我们创建jt-sso的目的就是让jt-web服务器去跨域访问我们jt-sso服务器,让jt-sso服务器去查redis缓存也好,去查我们的mariadb数据库也好,来确认我们的用户注册或者登陆的时候是否是合法操作。

在这里插入图片描述

选择jar包
在这里插入图片描述

添加继承/依赖/插件

在这里插入图片描述

编辑POJO对象User
在这里插入图片描述

构建JT-SSO代码

在这里插入图片描述

编写jt-sso配置文件

在这里插入图片描述

编辑nginx配置文件

在这里插入图片描述

创建单点登录测试代码

在这里插入图片描述

在这里插入图片描述

跨域案例

案例1:
页面网址:http://manage.jt.com:80/test.html
ajax请求: http://manage.jt.com:80/test.json
结论: 当请求协议://域名:port端口号都相同时 访问正常的.
在这里插入图片描述

案例2:
页面网址: http://www.jt.com:80/test.html 前端jt-web服务器
ajax请求: http://manage.jt.com:80/test.json 后端端jt-manage服务器
结论: 当浏览器的地址与ajax地址不同时,请求不能正常执行.(协议,ip地址[这里不同],端口)

在这里插入图片描述

同源策略说明

说明:浏览器在发起AJAX请求时,必须遵守同源策略的规定.否则数据无法正常解析.
策略说明: 发起请求时,必须满足 协议://域名:端口都相同(和当前页面对比)时.满足同源策略要求.浏览器可以正确的发起请求,并且解析结果.。
但是如果上述的三项中有一项不同,则表示跨域访问.浏览器不予解析返回值结果。

重点总结: 条件1:浏览器在发起AJAX请求时 条件2:协议://域名:端口都相同
条件1是必须要满足的,而当条件2中的协议或者域名或者端口号只要有一个地方不同,就是跨域访问(必须与后面的远程调用区分开来)
在这里插入图片描述

例题: 问http://manage.jt.com/test.html 和http://localhost:8091/test.json 能否通信?
答案: 不能通信 1.域名不一致 2.端口不同
解析:manage.jt.com和localhost:8091本质上是同一台服务器,仅仅只是经过nginx反向代理而显示不同。但是即使是这样这两个的域名还是不同,端口号也是不同一个是8091另一个是80,这我们也要清除的区分开来。

什么是跨域(重点理解)

定义: 当浏览器解析ajax时,ajax发起请求的地址如果与当前页面所在的地址违反同源策略时,则称之为跨域(请求)

跨域的实现方式(JSONP,CorS)

JSONP(难)

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的

JSONP跨域实现原理
在这里插入图片描述

JSONP的过渡案例
在这里插入图片描述

1).利用javascript中的src属性实现跨域

<script type="text/javascript" src="http://manage.jt.com/test.json"></script>

2).自定义回调函数 function callback(){}

为什么要定义回调函数???
原因:我们现在所在的服务器是jt-web前端服务器,我们想模仿script标签中的src属性去获取后端服务器的json数据,但是我们就仅仅这一个请求是没有办法拿到数据的,这样我们的json数据只会永远的存在浏览器的内存内部。因为没有名字怎么调用呢?所以我们直接给后端服务器的json数据起了一个hello的名字,然后再我们jt-web前端服务器手写一个回调函数就能实现跨域的效果了,我们就是这么解决这个问题的。

		function hello(data){
			alert(data.name);
		}

3).将返回值结果 进行特殊的格式封装 callback(JSON数据)

注意:这个定义是在jt-manage后端服务器的test.json中定义的

hello({"id":"1","name":"dengjinghui"})

jQuery优化/实现JSONP跨域访问

为什么要使用jquery优化我们的跨域访问呢???
原因:使用script标签确实可以实现跨域,但是我们正常来说会这么写吗?一般我们喜欢实现跨域的形式就是直接发起ajax请求,然后直接跨域。并且这个回调函数是谁写的?是我们自己写的。今天我们这个回调函数的名字叫做hello,但是一旦我们换了名字是不是就无法实现跨域了呢?是的。我们想自动生成一个函数,你连回调函数都别写了,这样用户调用也更加方便。基于这一系列问题,我们就想优化。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONP测试</title>
//注意:这里远程访问后端服务器jt-manage的js函数类库,后端服务器必须是开着的,现在开着两台服务器,后端服务器不开是没有办法获取js函数类库的。
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
	$(function(){
		alert("测试访问开始!!!!!")
		$.ajax({
			url:"http://manage.jt.com/web/testJSONP",
			type:"get",				//jsonp只能支持get请求(src里面不支持post提交,也只能写get请求)
			dataType:"jsonp",       //dataType表示返回值类型(如果是跨域访问,这一行必须写,不写仅仅表示普通的ajax)
			//jsonp: "callback", //指定参数名称(默认的名字就是callback,如果我们这里叫abc,controller中的参数也得叫abc才可以)
			//jsonpCallback: "hello",  //指定回调函数名称(如果觉得后面的名字很长可以换自己想要的名字)
			success:function (data){   //data经过jQuery封装返回就是json串
				alert(data.id);
				alert(data.password);
				//转化为字符串使用
				//var obj = eval("("+data+")");
				//alert(obj.name);
			}	
		});	
	})
</script>
</head>
<body>
	<h1>JSON跨域请求测试</h1>
</body>
</html>

页面url分析
在这里插入图片描述

编辑JSONPController

@RestController  //因为返回的数据都是json数据
public class JSONPController {
	
	/**
	 * jt-web请求的url地址:http://manage.jt.com/web/testJSONP?callback=jQuery111100158921719617664_1597461345316&_=1597461345317
	 * 
	 * 参数:callback (本来需要我们手动的写一个回调函数的们,现在不需要)
	 * 
	 * 返回值: JSONPObject 专门负责封装JSONP的返回值结果的(如果使用jquery的JSONP形式,返回值就是它,没有原因)
	 * 注意事项:  返回值结果必须通过特殊的格式封装    callback(JSON数据)
	 */
	
	@RequestMapping("/web/testJSONP")
	public JSONPObject jsonp(String callback){
		User user = new User();
		user.setPassword("123456789我是密码").setId(666l);
		return new JSONPObject(callback, user);
		//return new JSONPObject(function, value)
	}
}

CORS(简单)

CORS跨域实现原理

说明:当下的主流的浏览器天生都支持跨域,通过添加请求头信息,将源地址进行标识,之后发往后端服务器.
在这里插入图片描述

在这里插入图片描述

关键点:跨域请求由浏览器和服务器共同完成,.要求双方都必须同意跨域才行. 但是默认的条件下服务器端是不允许跨域的.所以必须经过配置才行。

在这里插入图片描述
说明:浏览器发起了ajax请求到后端服务器获取数据的时候,然后拿到了后端服务器响应的数据去校验,发现了违反了同源策略,因为后端服务器默认并不允许跨域访问,所以浏览器就不处理数据返回值了,不与解析返回值,因为浏览器也认为你的数据是不安全的。因为我们浏览器说要跨域,而jt-manage后端服务器并不允许跨域。所以规则就是这样,请求可以发,也可以返回,但是我浏览器要校验一下返回值的时候到查看你后端服务器到底允许不允许跨域访问,如果后端服务器不允许我们浏览器也不予解析数据。

CORS实现跨域

说明:在jt-common中添加跨域配置

//类似于web项目中使用的web.xml配置文件
@Configuration
public class CorsConfig implements WebMvcConfigurer{
	
	/**
	 * 配置后端服务器可以跨域的清单
	 * 参数说明:  addMapping:什么样的请求可以进行跨域   /web/**    /aaa/b/c/e/d/d/d
	 *          /*   匹配一级目录
	 *          /**  匹配多级目录   使用最多
	 */
	public void addCorsMappings(CorsRegistry registry) {
		
		registry.addMapping("/**")
				.allowedOrigins("*")    //配置源 通配,表示任何都可以。不仅仅前端要跨域,可能其它也要跨域,现在http://www.jt.com/
				.allowedMethods("GET","POST","PUT","DELETE","HEAD") //允许的请求方式
				.allowCredentials(true)		//是否允许携带cookie
				.maxAge(1800);				//允许跨域的持续时间   单位s 30分钟
	}
}

编辑ajax请求页面

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>
<script type="text/javascript" src="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
	/*$(){}结构必然是jQuery函数类库导入后才能正确执行*/
	$(function(){
		alert("我执行了AJAX");
		//利用jQuery发起AJAX请求
		$.get("http://manage.jt.com/web/testCors",function(data){
			alert(data.id);
			alert(data.name);
		})
	})
</script>
</head>
<body>
	<h1>JSON跨域请求测试</h1>
</body>
</html>

编辑CorsController

@RestController
public class CorsController {
	/**
	 * url请求地址:http://manage.jt.com/web/testCors
	 * 
	 * 参数无
	 * 
	 * 返回值User对象 (仅仅为了测试数据,没有别的意思)
	 */
	@RequestMapping("/web/testCors")
	public User testUser(){
		System.out.println("我执行了业务");
		return new User().setId(666l).setUsername("dengjinghui");
	}
}

//已经测试成功,一切正常

jt-web校验注册用户是否存在

业务需求分析:当用户添加注册信息时,需要向JT-SSO单点登录系统进行数据的校验.如果数据库中存在/不存在都应该返回相关信息,之后页面提示信息给用户
在这里插入图片描述

页面JS分析
在这里插入图片描述

Sts快速检索数据的方法 ctrl+h

在这里插入图片描述

说明:配置ajax实现JSONP的请求

在这里插入图片描述

业务接口文档
在这里插入图片描述

编辑UserController

在这里插入图片描述

编辑UserService

public class UserServiceImpl implements UserService {
	
	@Autowired(required = false)
	private UserMapper userMapper;
	
	private static Map<Integer,String> paramMap;//如果项目中固定写死的可以通过static方式维护
	
	static {
		Map<Integer,String> map = new HashMap<Integer,String>();//这么写为了的就是只有一份
		map.put(1, "username");
		map.put(2, "phone");
		map.put(3, "email");
		paramMap =  map;
	}
	@Override
	public Boolean findUser(String param, Integer type) {
		//1 username、2 phone、3 email
		String column = paramMap.get(type);
		
		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
		queryWrapper.eq(column,param);//假如是1  相当于select username from tb_user where username='param'
		//1.通过获取数据库中的记录总数,判断是否存在数据
		int count = userMapper.selectCount(queryWrapper);
		return count>0?true:false;
	}
}

再次编辑UserController

/**
	 * url请求地址:http://sso.jt.com/user/check/{param}/{type}
	 * 
	 * 参数 :param 需要校验的数据,即是用户在输入框输入的数据 typeType为类型,可选参数1 username、2 phone、3 email
	 * 例如:用户如果在注册页面的用户名输入框中注入内容传的type就是1对应数据库的字段就输username,在验证手机里输入内容传入的type是2
	 * 对应数据库的字段就是phone
	 * 
	 * 返回值:SysResult对象(看接口文档结合前端js知道的)
	 * 
	 */
	
	@RequestMapping("/check/{param}/{type}")
	public JSONPObject findUser(@PathVariable String param,@PathVariable Integer type,
			String callback){//默认的不写就是callback
		
		Boolean flag = userService.findUser(param,type);
		SysResult sysResult =  SysResult.success(flag);
		return new JSONPObject(callback, sysResult);
	}

正确的页面效果
在这里插入图片描述

添加状态码的判断编辑jdValidate.js

 $.ajax({
            	url : "http://sso.jt.com/user/check/"+escape(pin)+"/1?r=" + Math.random(),
            	dataType : "jsonp",
            	success : function(data) {
                    checkpin = data.data?"1":"0";
                    //校验服务器数据是否正确
                    if(data.status == 200){
                    	 //返回值data.data=true 已存在/false 不存在
                        if (!data.data) {
                            validateSettings.succeed.run(option);
                            namestate = true;
                        }else {
                            validateSettings.error.run(option, "该用户名已占用!");
                            namestate = false;
                        }
                    }else{
                    	 validateSettings.error.run(option, "服务器正忙,请重试!!!");
                         namestate = false;
                    }
                   
                }
            });

说明:添加后我们会发现一个问题,我们故意让UserController报错,状态值不是200,而是201,但是我们的注册页面依然没有办法告诉我们 "服务器正忙,请重试!!!"这是我们写好的js的效果!为什么在页面没有显示这样的提示呢!而仅仅是我们的后端服务器报了错,前端页面一点提示都没给用户!非常不友好,用户也不知道发生了什么事。
在这里插入图片描述
**原因:**因为这里出了错,导致我们的返回值结果不能用,因为只有当我们的业务正确的时候上面才能正确的把结果返回。但是要是错误的时候,我们之前定义了一个全局异常处理机制。而我们之前写好的全局异常处理机制的返回值是SysResult对象,但是这么写是有风险的,因为仅仅当是普通的请求发生了异常返回值是SysResult对象,但是一旦涉及到了我们的跨域访问返回值就不再是SysResult对象了。所以是我们的全局异常处理机制写的不好,导致现在我们是跨域访问出现了异常没有办法正确显示我们写好的js异常提示,现在我们需要优化我们的全局异常处理机制的问题。

全局异常处理类的优化

优化前:
在这里插入图片描述
优化后:记住HttpServletRequest request这个对象可以获取向我们服务器发起请求的所有信息

@Slf4j //默认提供一个log对象,打印日志
@RestControllerAdvice
public class SystemExceptionAop {

/**
	 * 添加通用异常返回的方法.
	 * 底层原理:AOP的异常通知.
	 * 
	 * 常规手段:  SysResult.fail();
	 * 
	 * 跨域访问:  JSONP   必须满足JSONP跨域访问要求  callback(SysResult.fail())
	 * 问题: 如何断定用户使用的是跨域方式还是普通业务调用??? 
	 * 分析: jsonp请求   get请求的方式携带?callback   
	 * 判断依据:  用户参数是否携带callback  特定参数,一般条件下不会使用
 */
	@ExceptionHandler({RuntimeException.class}) //加上花括号是为了后面可能会写多个,异常之间用逗号隔开
	public Object systemResultException(HttpServletRequest request,Exception exception){
		String callback = request.getParameter("callback");
		if(StringUtils.isEmpty(callback)){ //因为跨域访问必定携带callback参数,如果为空就证明不是跨域访问,按正常返回结果
			log.error("{~~~~~~~~~"+exception.getMessage()+"}",exception);//打印日志到控制台,这个log对象是Slf4j提供的
			return SysResult.fail(); //如果在controller出现了异常都是返回我们写好的结果,减少我们写try-catch代码
		} 
		String method = request.getMethod();
		//说明:有可能跨域  jsonp只能提交GET请求
		if(!method.equalsIgnoreCase("GET")){ //忽略大写写判断请求是否是get请求,加个非取反。不是跨域访问,按正常返回结果
			log.error("{~~~~~~~~~"+exception.getMessage()+"}",exception);
			return SysResult.fail(); 
		}
		
		//3.如果程序执行到这里,标识进行了JSONP的请求. 按照JSONP的方式返回数据(已确定必定是跨域反问了)
		log.error("{~~~~~~~~~"+exception.getMessage()+"}",exception);
		return new JSONPObject(callback,SysResult.fail());
	}
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值