商城项目第一天
黑马商城项目功能演示
功能模块
- 用户模块
- 登录
- 注册
- 退出
- 修改
- 商品模块
- 商品的展示
- 分类展示
- 购物车模块
- 订单模块
- 在线支付
- 后台管理模块
今日任务
- 完成用户模块
- 注册
- 登录
- 退出登录
前后端分离
所有用到的展现数据都是后端通过异步接口(AJAX/JSON)的方式提供的,前端只负责展现内容
前端: 前端开发人员复制页面的显示效果,AJAX从服务器端获取数据,如何展示数据由前端开发人员决定
后端:Web服务器开发人员负责将JSON数据回传客户端,无需在对客户端显示内内容控制
前后端开发人员通过接口文档进行约定接口信息
开发环境搭建
- Maven骨架创建Web应用程序
- 前端开发工具编写网页(有关前端开发工具hbuilder的环境搭建
AJAX跨域访问
跨域问题来源于JavaScript的同源保护策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。
解决此问题分为前后端两部分:
- 前端部分:
//使用jquery发送ajax请求的时候 额外设置属性
$.ajax({
url:url,
dataType:"json",
data:parameter,
xhrFields: {
//允许接受从服务器端返回的cookie信息 ,默认值为false 也就是说如果必须设置为true的时候 才可以接受cookie 并且请求带上
withCredentials: true
},
success:function (data,status,xhr) {
//处理登录的filter
if(true){
fn(data,status,xhr);
}
}
})
- 后端部分:
//解决跨域访问数据问题
response.setHeader("Access-Control-Allow-Origin", "http://www.itheima326.com:8020");
//AJAX访问允许客户端保存cookie
response.setHeader("Access-Control-Allow-Credentials","true");
另一种方式
//获取请求的来源网站
String origin = request.getHeader("Origin");
//允许你访问我 但是不允许设置cookie
response.setHeader("Access-Control-Allow-Origin",origin);
//允许浏览器发送cookie
response.setHeader("Access-Control-Allow-Credentials","true");
域名解析服务器
输入域名后先找DNS服务器解析成ip地址,然后才访问
BaseServlet抽取
public class BaseServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
//获取方法调用的参数
String method = request.getParameter("method");
Method m = this.getClass().getDeclaredMethod(method, HttpServletRequest.class, HttpServletResponse.class);
m.invoke(this, request, response);
}catch (Exception ex){ex.printStackTrace();}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
成功响应和失败响应抽取
public void success(Object data) throws IOException {
ResultVo vo = new ResultVo(ResultVo.CODE_SUCCESS,data,"");
String s = new ObjectMapper().writeValueAsString(vo);
RRHolder.getResponse().getWriter().print(s);
}
public void fail(Object data) throws IOException {
ResultVo vo = new ResultVo(ResultVo.CODE_FAILED,data,"");
String s = new ObjectMapper().writeValueAsString(vo);
RRHolder.getResponse().getWriter().print(s);
}
用户注册实现
注册实现步骤:
- 客户端发起AJAX请求,表单数据提交到服务器Servlet
- Servlet接收客户端请求数据并封装JavaBean
- 调用业务层方法
- 业务层调用持久层方法
- Servlet将注册结果封装对象,向客户端回写JSON数据
- 客户端判断JSON数据,跳转页面
注册页面
ajax
<script>
$(function(){
$("#registBtn").click(function(){
//把form里的表单数据以键值对的形式取出来
var params = $("form").serialize();
//1.访问的servlet 2.访问时带的参数 3.成功回调函数
HM.ajax("/user?md=regist",params,function(vo){
if(vo.code==1){
location.href="login.html";
}else{
var errorString = vo.data;
$("#username_error").html(errorString).css("color","red");
}
})
})
})
</script>
servlet
protected void regist(HttpServletRequest request,HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
if(username==null||username.trim().length()>6||username.trim().length()<2){
fail("username的长度在2-6之间");
return;
}
Map<String, String[]> parameterMap = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user,parameterMap);
user.setUid(UUIDUtil.getId());
new UserService().save(user);
success(null);
} catch (Exception e) {
e.printStackTrace();
}
}
dao
public void save(User user) {
QueryRunner queryRunner = new QueryRunner(DataSourceUtil.getDataSource());
String sql = "insert into user(uid,username,password,name,email,birthday,gender,remark)values(?,?,?,?,?,?,?,?)";
Object[] params = {user.getUid(),user.getUsername(),user.getPassword(),user.getName(),user.getEmail(),user.getBirthday(),user.getGender(),user.getRemark()};
try {
queryRunner.update(sql,params);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
用户登录实现
登录实现步骤:
- 客户端发起AJAX请求,表单数据提交到服务器Servlet
- Servlet接收客户端请求数据并传递到业务层
- 调用业务层方法获取返回值
- 业务层调用持久层方法
- Servlet将登录结果封装成对象,返回JSON数据
- 登录成功保存session
- 用户名姓名保存在cookie中,回写浏览器
- 客户端判断JSON数据,跳转页面
- 客户端在页面顶部显示登录的用户名
登录功能页面
ajax
<script type="text/javascript">
$(function () {
$("#loginBtn").click(function(){
var params = $("#loginForm").serialize();
HM.ajax("/user?md=login",params,function(vo){
if(vo.code==1){
location.href="index.html";
}else{
$("#error").html(vo.data).css("color","red");
}
})
})
})
</script>
servlet
protected void login(HttpServletRequest request,HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = new UserService().findUserByUAP(username,password);
if(user!=null){
request.getSession().setAttribute("user",user);
success(null);
}else{
fail("用户名或者密码不正确");
}
}
dao
public User findUserByUAP(String username, String password) {
QueryRunner queryRunner = new QueryRunner(DataSourceUtil.getDataSource());
String sql = "select * from user where username = ? and password = ?";
Object[] params = {username,password};
try {
User user = queryRunner.query(sql, new BeanHandler<User>(User.class), params);
return user;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
Header页面的用户名显示
ajax
HM.ajax("/user?md=currentname","",function(vo){
if(vo.code==1){
var nickname = vo.data;
var li = "<li>"+nickname+":欢迎你</li>";
li+="<li><a href='javascript:;' οnclick='logout()'>注销登录</a></li>"
li+="<li><a href='http://www.bai.com:8020/store/view/cart/list.html'>购物车</a></li>"
li+="<li><a href='http://www.bai.com:8020/store/view/order/list.html'>我的订单</a></li>"
$("#login-menu").html(li)
}else{
}
})
HM.ajax("/category?md=list","",function(vo){
})
})
servlet
protected void currentname(HttpServletRequest request,HttpServletResponse response) throws IOException {
User user = (User) request.getSession().getAttribute("user");
if(user!=null){
String name = user.getUsername();
success(name);
}else{
fail(null);
}
}
退出登录
实现步骤
- 点击退出登录按钮
- 服务器端销毁session对象
- 客户端跳转到首页
ajax
HM.ajax("/category?md=list","",function(vo){
})
servlet
protected void logout(HttpServletRequest request,HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
session.invalidate();
success(null);
}
}
本地线程封装
谁放的谁取,封装request和response,方便获取使用
RRHolder
public class RRHolder {
private static final ThreadLocal<HttpServletRequest> requestThreadLocal = new ThreadLocal<>();
private static final ThreadLocal<HttpServletResponse> responseThreadLocal = new ThreadLocal<>();
public static void setRequest(HttpServletRequest request){
requestThreadLocal.set(request);
}
public static void setResponse(HttpServletResponse response){
responseThreadLocal.set(response);
}
public static HttpServletRequest geRequest(){
return requestThreadLocal.get();
}
public static HttpServletResponse getResponse(){
return responseThreadLocal.get();
}
}
RRFilter
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
RRHolder.setRequest(request);
RRHolder.setResponse(response);
chain.doFilter(req, resp);
}
测试两端是否畅通
前端页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="resources/js/jquery-1.11.3.min.js" ></script>
<script>
function req(){
$.ajax({
type:"get",
url:"http://api.itheima349.com:80/test",
data:"username=xiaoming",
success:function(data){
alert(data);
},
error:function(){
//.....
}
});
}
</script>
</head>
<body>
<div>
<input type="button" value="点我试试后端行不行" onclick="req()" />
</div>
</body>
</html>
后端页面
@WebServlet("/test")
public class TestServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
System.out.println("前端传来参数:"+username);
//response.setHeader("Access-Control-Allow-Origin","http://www.itheima349.com:8020");
response.getWriter().print("后端启动");
}
}
测试两端cookie问题
前端
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="resources/js/jquery-1.11.3.min.js" ></script><br />
<script type="text/javascript" src="resources/js/jquery-heima-0.0.1.js" ></script>
<script>
function req(){
/*$.ajax({
type:"get",
url:"http://api.itheima349.com:80/testcookie",
data:"username=xiaoming",
success:function(data){
alert(data);
},
error:function(){
//.....
},
xhrFields:{
//允许服务器端给发送cookie 我会保存 并且允许客户端往回带cookie
withCredentials:true
}
});
*/
HM.ajax("/testcookie","username=xiaoming",function(data){
alert(data)
})
}
</script>
</head>
<body>
<div>
<input type="button" value="点我试试后端行不行" onclick="req()" />
</div>
</body>
</html>
后端
public class CookieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
System.out.println("前端传来参数:"+username);
//尝试获取
Cookie[] cookies = request.getCookies();
if(cookies!=null&&cookies.length>0){
for (Cookie cookie : cookies) {
System.out.println("cookie的名字:"+cookie.getName()+"-----cookie的值:"+cookie.getValue());
}
}
//设置一个cookie
Cookie cookie = new Cookie("name", "xyz");
cookie.setMaxAge(60*60);
cookie.setPath("/");
response.addCookie(cookie);
response.getWriter().print("测试cookie");
}
}
测试两端交互数据json格式
前端
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="resources/js/jquery-1.11.3.min.js" ></script><br />
<script type="text/javascript" src="resources/js/jquery-heima-0.0.1.js" ></script>
<script>
function req(){
HM.ajax("/testjson","username=xiaoming",function(vo){
alert(vo.data[1])
})
}
</script>
</head>
<body>
<div>
<input type="button" value="点我试试后端行不行" onclick="req()" />
</div>
</body>
</html>
后端
public class JsonServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//后端返回的是一个json格式数据
//希望返回一个 成功与否
//这次业务返回 你好
/*ResultVO resultVO = new ResultVO();
resultVO.setData("你好");
resultVO.setCode(1);
resultVO.setDesc("正常返回的描述信息");*/
//这次项返回 的是个数组
ResultVo resultVO = new ResultVo();
String[] ss=new String[]{"夏明","夏红","夏雨"};
resultVO.setData(ss);
resultVO.setCode(ResultVo.CODE_SUCCESS);
resultVO.setMessage("正常返回的描述信息");
String s = new ObjectMapper().writeValueAsString(resultVO);
response.getWriter().print(s);
}
}
JavaScript特性
<script>
var HM={
xxxx:"你好",
sayhello:function(){
alert("我是一个函数")
}
}
//alert(HM.xxxx)
HM.sayhello()
</script>
hosts文件修改
进入该目录
C:\Windows\System32\drivers\etc
打开hosts文件
新增记录
127.0.0.1 www.itheima.com
127.0.0.1 api.itheima.com