1 系统中的事务问题
1.1 Spring默认的事务策略
1.1.1 关于代码中的try-catch
说明:
由于代码中采用spring的声明式的事务处理,所有程序员我需关注事务控制,统统交给spring管理.
Spring要求,如果出现了运行时异常,spring才会回滚事务.
如果在代码中对入库操作添加了try-catch ,则spring容器不能接收异常信息,所以不会回滚事务.
总结:tyr-catch不要加到入库和更新操作上.尽量控制其范围.
2 单点登录
2.1 单点登录介绍
2.1.1 什么是单点登录
说明:用户一次登录后,可以免密登录其相关系统
2.1.2 SSO分析
说明:
当用户登陆QQ游戏时 ,进行了登陆操作,当访问QQ邮箱时,需要再次登录,因为Session没有共享,是不同的对象.所以数据不能公用.
2.1.3 单点登录设计图
2.1.4 单点登录说明:
1.当用户第一次登陆时,先通过SSO单点登录系统进行登录操作.
2.根据用户信息查询用户数据验证登录是否有效
3.如果用户名和密码都正确,则生成ticket.并将User对象转化JSON数据
4.将ticket和UserJSON数据写入redis缓存中
5.当用户登陆成功后,在cookie保存ticket信息.
6.当用户再次访问前台系统时,首先根据ticke信息,查询redis缓存服务器.获取用户数据.
7.当用户访问购物车时,首先前台会校验,根据ticket查询用户信息,如果用户没有登陆则转向单点登录系统.
8.当用户访问订单系统时,首先前台会校验,根据ticket查询用户信息,如果没有该用户信息,则转向单点登录系统.
2.2 构建SSO单点登录服务器
2.2.1 SSO项目说明
单点登录服务器.需要操作数据库,所以构建时需要Controller.Service.Mapper一同完成.
构建web项目.
2.2.2 构建web项目
选择web骨架创建项目
引入jt-parentjar包
引入common
2.2.3 导入tomcat插件
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8093</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
为sso添加启动项
2.2.4 修改Nginx实现转向
说明:通过nginx实现sso.jt.com的转发
#京淘项目单点登录
server {
listen80;
server_namesso.jt.com;
location/ {
proxy_passhttp://127.0.0.1:8093;
}
}
Nginx修改完成之后 重启nginx
nginx -s reload
2.2.5 修改HOST文件
添加host文件.保证访问sso.jt.com访问本机地址.
2.3 导入配置文件
2.3.1 拷贝jt-manage的配置文件
2.3.2 修改springMVC.xml
2.3.3 修改Spring的配置文件
2.3.4 修改Mybatis配置文件
修改pojo的包路径 和mapper的包路径
2.3.5 修改web.xml配置文件
拷贝:manage.jt.com的web.xml配置文件.到jt-sso单点登录中.
<?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/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="jt-manage"version="2.5">
<display-name>jt-sso</display-name>
<!--配置监听器启动spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring/applicationContext*.xml</param-value>
</context-param>
<!--1.配置前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置加载SpringMVC.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/spring/springmvc.xml</param-value>
</init-param>
</servlet>
<!--
/ 规定
1.表示拦截全部的请求
2.拦截所有静态资源js/css/image 后期配置放行
3.放行.jsp资源
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置全站乱码解决 POST乱码 -->
<filter>
<filter-name>characterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<!--定义默认字符集utf-8 -->
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
3 登录业务逻辑
3.1 京淘前台登录跳转
3.1.1 登录/注册的跳转
@Controller
@RequestMapping("/user")
publicclass UserController {
///user/register.html实现登录和注册页面跳转
///user/login.html
@RequestMapping("/{param}")
public String module(@PathVariable String param){
//转向用户登陆和注册页面
returnparam;
}
}
4 用户注册的校验
4.1 页面JS分析
4.1.1 JS查找
说明:
url:http://sso.jt.com/user/check/admin123/1?r=0.26835501213441115&callback=jsonp1517465570159&_=1517465578846
说明:
页面中通过JSONP的形式直接访问SSO单点登录系统,校验用户名/密码是否存在
4.2 SSO代码编辑
4.2.1 接口文档
请求方法 |
GET |
URL |
http://sso.jt.com/user/check/{param}/{type} |
参数 |
格式如:chenchen/1 其中chenchen是校验的数据 Type为类型,可选参数1 username、2 phone、3 email |
示例 |
http://sso.jt.com/user/check/chenchen/1 |
返回值 |
{ status: 200 //200 成功,201 没有查到 msg: “OK” //返回信息消息 data: false //返回数据true用户已存在,false用户不存在,可以 } |
|
|
4.2.2 编辑POJO对象
@Table(name = "tb_user")
public class User extends BasePojo{
@Id //表示主键信息
@GeneratedValue(strategy=GenerationType.IDENTITY) //主键自增
private Long id; //用户的Id
private String username; //用户名
private String password; //密码 采用MD5加密
private String phone; //电话
private String email; //邮箱
4.2.3 编辑Mapper接口
public interface UserMapper extends SysMapper<User>{
//查询数据是否存在 将数据封装为Map
int findCheckUser(@Param("param")String param,@Param("cloumn")Stringcloumn);
}
在mybatis文件中编辑userMapper.xml映射文件
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jt.sso.mapper.UserMapper">
<!--使用#号获取数据的值,一般建议使用,因为有预编译的效用.
$符使用时,只会出现在以列名为参数的应用.
能用#号不用$
如果在列名的字段中使用#{}取值,相当于
SELECT COUNT(*) FROM tb_user WHERE "username"= 'admin123'
-->
<select id="findCheckUser"resultType="int">
select count(*) from tb_user where ${cloumn}= #{param}
</select>
</mapper>
4.2.4 创建service接口和实现类
publicinterface UserService {
//校验数据是否存在
Boolean findCheckUser(String param,Integer type);
}
4.2.5 编辑Service实现类
@Service
publicclass UserServiceImpl implementsUserService {
@Autowired
private UserMapper userMapper;
//Type为类型,可选参数1 username、2 phone、3 email
//SELECT COUNT(*)FROM tb_user WHERE username= 'admin123'
@Override
public Boolean findCheckUser(String param, Integer type) {
String cloumn = null;
switch (type) {
case 1: cloumn = "username"; break;
case 2: cloumn = "phone"; break;
case 3: cloumn = "email"; break;
}
//1,0
intcount = userMapper.findCheckUser(param,cloumn);
returncount ==1 ? true : false;
}
}
4.2.6 编辑Controller
//校验用户的注册信息
//url:http://sso.jt.com/user/check/admin123/1?callback=jsonp1517465570159&_=1517465578846
//1 username、2 phone、3 email
@RequestMapping("/check/{param}/{type}")
@ResponseBody
public Object checkUser(@PathVariableString param,@PathVariable Integer type,String callback){
try {
//根据传递的参数判断数据是否存在
Boolean result = userService.findCheckUser(param,type);
//返回JSONP的数据
MappingJacksonValue jacksonValue=
new MappingJacksonValue(SysResult.oK(result));
jacksonValue.setJsonpFunction(callback);
returnjacksonValue;
} catch (Exception e) {
e.printStackTrace();
returnnull;
}
}
4.3 用户的注册
4.3.1 JS请求
http://www.jt.com/service/user/doRegister
4.4 用户的登陆
4.4.1 登陆的思路
1.当用户点击登陆操作时,跳转到登陆页面
2.用户输入用户名和密码后点击登陆按钮发出请求.进行登录操作.
3.浏览器发出请求:
http://www.jt.com/service/user/doLogin?r=0.582247581950398
4.根据url接收用户名和密码数据
5.再次校验用户名和密码是否为空
6.转向登录页面(js中已将实现)
7.如果用户名和密码都不为null,则调用
8.UserService 通过httpClient方式发送数据
9.如果获取的ticket不为null.则表示登录操作成功.如果ticket为null,直接返回null.
将ticket信息写入到Cookie中
4.5 实现前台的登陆操作
4.5.1 页面分析JS
JS:http://www.jt.com/service/user/doLogin?r=0.582247581950398
4.5.2 编辑UserController
//用户登陆 http://www.jt.com/service/user/doLogin?r=0.582247581950398
//通过login.jsp检测登陆的username和password是否正确
@RequestMapping("/doLogin")
@ResponseBody
public SysResult doLogin(String username,String password,
HttpServletRequest request,HttpServletResponseresponse){
//判断用户名和密码是否为null
if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){
return SysResult.build(201, "用户名密码不能为空");
}
//当前输入的用户名是正确的
try {
//获取用户的ticket
String ticket =
userService.findUserByUP(username,password);
//ticket不为空
if(!StringUtils.isEmpty(ticket)){
//如果ticket数据不为空 则写入cookie
//Cookie[] cookies = request.getCookies();
//Cookie的名称必须为 JT_TICKET
CookieUtils.setCookie(request, response, "JT_TICKET", ticket);
return SysResult.oK(ticket);
}
} catch (Exception e) {
e.printStackTrace();
}
return SysResult.build(201, "用户登陆失败");
}
4.5.3 编辑UserService
@Override
public String findUserByUP(String username, String password) {
String uri = "http://sso.jt.com/user/login";
Map<String, String> map = new HashMap<String,String>();
//注意不要有空格
map.put("username", username);
map.put("password", password);
try {
String resutJSON = httpClient.doPost(uri,map);
//判断数据是否有效 将其转化为Sysresult对象
SysResult sysResult =
objectMapper.readValue(resutJSON,SysResult.class);
//判断SSO返回是否正确
if(sysResult.getStatus() == 200){
return (String) sysResult.getData();
}
} catch (Exception e) {
e.printStackTrace();
}
returnnull;
}
5 作业:
1. 试着完成用户登陆操作.
2. 试写用户登陆回显操作
说明:当用户登陆成功后,页面会发出请求.根据ticket从redis中查询用户信息
请求路径:http://sso.jt.com/user/query/ticket信息
根据业务接口文件,查询用户信息.
最终实现效用: