javaWeb综合案例

商城案例

        分模块:用户模块→ 分类模块 → 商品模块→购物车模块(最难)→  订单模块
        后台模块(往前台的数据的增删改查)

        今日任务:   1用户注册
        a注册完成
        b给注册人发邮件
        2用户激活
        a 去邮箱激活发送的邮件
        3用户登录
        a 登录失败:回首页显示
        b 判断用户是否激活了邮件
        c 如果没激活让用户去激活,如果激活了首页展示
        4用户退出
        Session相关
        
        注意点:    
            1.数据库和表
        create database store;
        use store;

    用户表:
        CREATE TABLE `user` (
          `uid` varchar(32) NOT NULL,               //id号
          `username` varchar(20) DEFAULT NULL,      //账号
          `password` varchar(20) DEFAULT NULL,      //密码
          `name` varchar(20) DEFAULT NULL,          //姓名
          `email` varchar(30) DEFAULT NULL,         //注册电子邮件
          `telephone` varchar(20) DEFAULT NULL,     //联系电话
          `birthday` date DEFAULT NULL,             //生日
          `sex` varchar(10) DEFAULT NULL,           //性别
          `state` int(11) DEFAULT NULL,  // 0 未激活  1 已激活
          `code` varchar(64) DEFAULT NULL,  // 激活码 
          PRIMARY KEY (`uid`)               //主键    
          设置账号是否已经注销了,如果注销了,设置一个标记,标记已注销.
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  //设置编码格式

        servlet工具类的抽取:
            之前编写的servlet的问题:
                1.doget每次请求都会执行
                2.用了大量 if else if 判断执行的是那个方法让方法执行
                    Method method = this.getClass().getMethod(mt, HttpServletRequest.class,HttpServletResponse.class);
                    method.invoke(this, request,response);
                3.每个方法执行的结果无非就是请求转发或者重定向或者打印数据
                    让所有的方法都返回一个字符串
                        若最后的结果需要请求转发,就把转发的路径给返回
                        若最后的结果不需要请求转发,就返回一个null
                        
                        String path=method.invoke(this, request,response);
                        if(path != null){
                            request.getx(path).forward(...)
                        }
                4.所有servlet的service中的代码都一样
                    向上继续抽取
                    编写一个BaseServlet,将之前方法中的代码复制过来即可,
                    然所有的servlet都继承baseservlet即可

        今日难点:servlet工具类的抽取(baseServlet) :真正的企业开发中一个模块一个servlet


        1先搭建数据库
        2建立项目并且将页面信息加载进去
        3在外部建立一个index.jsp 跳转到servlet(list=封装热门商品--->请求转发到首页显示数据库面的信息)
         <%request.getrequestDispacher(“”);%>

        4找到登录页面中登录与注册入口 href=${}/jsp/jsp;
        //如果一个页面放在了WEB-INF文件下:不能被浏览器直接访问,只能通过代码访问,(通过Servlet)
           步骤: 在href= 标签里${pageContext....}/sd1
        创建一个servlet 名字为sd1
        doGet方法中使用请求转发 getRequestDispacher(需要访问的jsp);
         注意:之前做需求的时候一个功能一个Servlet,发现这样做的效率不高
         解决方案:一个模块一个servlet(UserServlet)
         实现方案:传参
         在href= 标签里${pageContext....}/sd1改成${pageContext....}/user?method=loginUI


        Servlet中的代码实现
        doGet()}{
        String method = request.getPatameter(“method”);
        If(loginUI.equals(method){
        //登录
        LoginUI(request,response);
        }else if(registUI.equals(method)){
        //注册
        RegistUI(request,response)
        }

        问:虽然传参方式满足了一个模块使用一个servlet但是if,else太多,不利于后期维护
        是否有什么方法解决?
        答:反射:传什么方法用什么方法

        Class.forName(“cn.baidu.web.UserServlet”)
        或者Class clazz =this.getClass();
        String me = request.getParameter(“method”))

         Method method = clazz.getMethod(me,HttpServletRequest.cass.....)
        String value = (String)Method.invoke(clazz.newInstance(),request,response)
        //做一个统一的请求转发
        If(value!=null){
        request.getRequestDispacher(Value).forward(request,response)
        }
        问:反射的方式解决了频繁编写 if else问题
        //虽然好处很大,但是只限于用户模块的功能,以后能不能所有的模块全部不需要在写了
        答:有:工具类的抽取(base extends HttpServlet)
        }


        //登录
        Public String  LoginUI( HttpServletRequest request){
        //到登录页面
        //request.getRequest.Dispacher(/jsp/login.jsp)
        Return “jsp/login.jsp”
        }
        //注册  重定向
        Public String  RegistUI( HttpServletRequest request){
        //注册
        //request.getRequest.Dispacher(/jsp/regist.jsp)
        Return “/jsp/regist.jsp ”

        }

        //重定向()
        Public String  zhuce(request,response){
        resonse.sendRedirect(“”)

        Return null;
        }

        5.创建一个servlet工具类base之后的servlet类只需要继承他并且去掉doGet与doPost,只需要写自己的方法就好,需要用doGet与doPost就找父类
        doGet()}{
        Try(){}
        Class.forName(“cn.baidu.web.UserServlet”)
        或者Class clazz =this.getClass();
        String me = request.getParameter(“method”))

         Method method = clazz.getMethod(me,HttpServletRequest.cass.....)
        String value = (String)method.invoke(clazz.newInstance(),request,response)
        //做一个统一的请求转发
        If(value!=null){
        request.getRequestDispacher(Value).forward(request,response)
        }
        问:反射的方式解决了频繁编写 if else问题
        //虽然好处很大,但是只限于用户模块的功能,以后能不能所有的模块全部不需要在写了
        答:有:工具类的抽取(base extends HttpServlet)
        }

        6.UerServlet(注册)
        表单提交 action, method=”post”
        隐藏域<input  tyoe =hidden, name=”method” value =’regist’>

        //日期控件......有资料,只读属性
        /把过滤器拿过来动态代理,编码
        配置文件XML中药配置一个filter
        Url->/*
        创建一个JAVABean(不要用int用Integer,int的默认值是0,Integer默认值是null)
        不和业务逻辑起冲突
        uid用UUID保证它唯一,激活码  uuid+uuid


        Public String regist(reqest,response){
        Try(){
        //获取注册的所有页面信息
        Map<String,String[]> map = request.getParameter();
        //创建一个bean
        User uer = new User();
        //把map中的数据封装到User中
        BeanUtils.populate(user,map);
        //设置主键uid
        user.setUid(UUID.randomUUID().toString().replace(“-”,””));
        //设置激活状态,刚注册的时候是未激活状态
        user.setState(0);
        //设置激活码 uuid+uuid
        user.setCode(...);
        //调用service
        //以后工作中的开发都是面向接口开发,好处是拓展性高
        UserServic us = new UserServiceImpl();//多态
        Us.regist(user);
        Syso(数据注册成功,可以给该用户发邮件了)

        //注册只要成功就给该用户发邮件一个工具类mailUtils,一个jar包
        //email就是收信人 emaliMsg是正文

        String emaliMsg = “”+user.getName()+”<a href=’http://httplocalhost:8080/store/user?method=active&code=’’+user.getCode()> 点击激活</a>”

        mailUtils.

        request.setAttribute(“msg”,”邮件发送成功,去邮件激活再登录”)
        }
        }catch(Exeption e){
        e.printStack...
        //请求转发到另一个页面
        request.setAttribute(“msg”,”注册失败,稍后继续..”);
        Return “ /jsp/**.jsp”
        }
        Return “/jsp/**.jsp”;
        }


        //激活
        Public String  active(Http..request,Http...response){
        Try{
        //先判断数据库中有没有该用户
        String code = request.getParameter(“code”);
        UserService us = new UserService();
         User user = us.findByCode(code);
        If(user==null){
        //代表该用户已经从数据库中移除了
        request.setAttibute(“msg”,”激活失效,重新注册”)
        Return ”/jsp/**.jsp”
        }
        //有的话就把状态码改成1
        user.setState(1);
        //提示信息,激活成功,去登录吧
        request.setAttrubute(“msg”,”激活成功去登录吧”)
        }catch(Exception e){
        request.setAttribute(“msg”,”查询用户失败,请稍后继续”)
        }

        Return “/jsp/**.jsp”
        }

        //登录的方法实现
        //也需要核实jsp中是否有这些name属性
        Public String  login((Http..request,Http...response){
        Try{
        HttpSession session = request.getSession();

        //获取用户名与密码
        String username = request.getParameter(“username”);
        String password = request.getParameter(“password”);
        //根据用户名和密码查询该用户
        UserService us = new UserServiceImpl();
        User user =us.findUser(username,password);
        If(user==null){
        Request.setA...(“msg”,”用户名或者密码错误”)
        Return “/jsp...”
        }
        //判断是否激活
        If(user.getState()!=1){
        Request.setA...(“msg”,”没有激活,先激活再登录”)
        Return “/jsp...”

        }

        //既有该用户也做了激活
        自动登录=Request--->javabean---->服务器关闭了-->request中数据没有了
        Session--->javabean--->服务器关闭了---->session没有销毁  永远可以从session中拿到javabean(用户的信息永远在session中)
        session.setA...(“user”,”user”);
        //重定向
        response.sendRedirect(request.getContextPath()+”/jsp/**.jsp”)

        //index.jsp中做el判断 登录注册购物车
        <c: if test=”${empty user}”>
        </c:if>

        <c: if test=”${ not empty user}”>
        “欢迎***登录”
        加一个购物车标签
        </c:if>

        }catch(){
        E.print.....
        Request.set...(“msg”,”失败”)
        Return “/jsp/**.jsp”

        }

        Return null;
        }

        //用户退出
        点击用户退出就干掉session,在index.jsp中用户退出标签中添加链接
        Public String  quit((Http..request,Http...response){
        Try{
        //获取session
        HttpSeesion session = request.getSession():
        Session.remove(“user”)
        //重定向
        response.sendRedirect.....
        Return null;

        }
        }
前台分类信息展示
                 从数据库获取导航条的信息展示
            
            分类商品的分页展示
                
            单个商品详情

            最新商品和热门商品展示

        特点: select

        所需要的表: 分类表, 商品表

        1.创建分类表
                CREATE TABLE `category` (
                  `cid` varchar(32) NOT NULL,
                  `cname` varchar(20) DEFAULT NULL,
                  PRIMARY KEY (`cid`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

        INSERT INTO `category` VALUES ('1','手机数码'),('172934bd636d485c98fd2d3d9cccd409','运动户外'),('2','电脑办公'),('3','家具家居'),('4','鞋靴箱包'),('5','图书音像'),('59f56ba6ccb84cb591c66298766b83b5','aaaa'),('6','母婴孕婴'),('afdba41a139b4320a74904485bdb7719','汽车用品');

        2 创建商品表
                CREATE TABLE `product` (
                  `pid` varchar(32) NOT NULL,
                  `pname` varchar(50) DEFAULT NULL,
                  `market_price` double DEFAULT NULL,
                  `shop_price` double DEFAULT NULL,
                  `pimage` varchar(200) DEFAULT NULL,
                  `pdate` date DEFAULT NULL,
                  `is_hot` int(11) DEFAULT NULL,  // 热门     0: 热门 1 不热门
                  `pdesc` varchar(255) DEFAULT NULL,
                  `pflag` int(11) DEFAULT NULL,  // 是否下架  0: 上架   1 下架  做逻辑删除的
                  `cid` varchar(32) DEFAULT NULL,
                  PRIMARY KEY (`pid`),
                  KEY `sfk_0001` (`cid`),
                  CONSTRAINT `sfk_0001` FOREIGN KEY (`cid`) REFERENCES `category` (`cid`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

        INSERT INTO `product` VALUES ('1','小米 4c 标准版',1399,1299,'products/1/c_0001.jpg','2015-11-02',1,'小米 4c 标准版 全网通 白色 移动联通电信4G手机 双卡双待',0,'1'),('10','华为 Ascend Mate7',2699,2599,'products/1/c_0010.jpg','2015-11-02',1,'华为 Ascend Mate7 月光银 移动4G手机 双卡双待双通6英寸高清大屏,纤薄机身,智能超八核,按压式指纹识别!!选择下方“移动老用户4G飞享合约”,无需换号,还有话费每月返还!',0,'1'),('11','vivo X5Pro',2399,2298,'products/1/c_0014.jpg','2015-11-02',1,'移动联通双4G手机 3G运存版 极光白【购机送蓝牙耳机+蓝牙自拍杆】新升级3G运行内存·双2.5D弧面玻璃·眼球识别技术',0,'1'),('12','努比亚(nubia)My 布拉格',1899,1799,'products/1/c_0013.jpg','2015-11-02',0,'努比亚(nubia)My 布拉格 银白 移动联通4G手机 双卡双待【嗨11,下单立减100】金属机身,快速充电!布拉格相机全新体验!',0,'1'),('13','华为 麦芒4',2599,2499,'products/1/c_0012.jpg','2015-11-02',1,'华为 麦芒4 晨曦金 全网通版4G手机 双卡双待金属机身 2.5D弧面屏 指纹解锁 光学防抖',0,'1'),('14','vivo X5M',1899,1799,'products/1/c_0011.jpg','2015-11-02',0,'vivo X5M 移动4G手机 双卡双待 香槟金【购机送蓝牙耳机+蓝牙自拍杆】5.0英寸大屏显示·八核双卡双待·Hi-Fi移动KTV',0,'1'),('15','Apple iPhone 6 (A1586)',4399,4288,'products/1/c_0015.jpg','2015-11-02',1,'Apple iPhone 6 (A1586) 16GB 金色 移动联通电信4G手机长期省才是真的省!点击购机送费版,月月送话费,月月享优惠,畅享4G网络,就在联通4G!',0,'1'),('16','华为 HUAWEI Mate S',4200,4087,'products/1/c_0016.jpg','2015-11-03',0,'华为 HUAWEI Mate S 臻享版 手机 极昼金 移动联通双4G(高配)满星评价即返30元话费啦;买就送电源+清水套+创意手机支架;优雅弧屏,mate7升级版',0,'1'),('17','索尼(SONY) E6533 Z3+',4099,3999,'products/1/c_0017.jpg','2015-11-02',0,'索尼(SONY) E6533 Z3+ 双卡双4G手机 防水防尘 涧湖绿索尼z3专业防水 2070万像素 移动联通双4G',0,'1'),('18','HTC One M9+',3599,3499,'products/1/c_0018.jpg','2015-11-02',0,'HTC One M9+(M9pw) 金银汇 移动联通双4G手机5.2英寸,8核CPU,指纹识别,UltraPixel超像素前置相机+2000万/200万后置双镜头相机!降价特卖,惊喜不断!',0,'1'),('19','HTC Desire 826d 32G',1599,1469,'products/1/c_0020.jpg','2015-11-02',1,'后置1300万+UltraPixel超像素前置摄像头+【双】前置扬声器+5.5英寸【1080p】大屏!',0,'1'),('2','中兴 AXON',2899,2699,'products/1/c_0002.jpg','2015-11-05',1,'中兴 AXON 天机 mini 压力屏版 B2015 华尔金 移动联通电信4G 双卡双待',0,'1'),('20','小米 红米2A 增强版 白色',649,549,'products/1/c_0019.jpg','2015-11-02',0,'新增至2GB 内存+16GB容量!4G双卡双待,联芯 4 核 1.5GHz 处理器!',0,'1'),('21','魅族 魅蓝note2 16GB 白色',1099,999,'products/1/c_0021.jpg','2015-11-02',0,'现货速抢,抢完即止!5.5英寸1080P分辨率屏幕,64位八核1.3GHz处理器,1300万像素摄像头,双色温双闪光灯!',0,'1'),('22','Galaxy S5 (G9008W)',2099,1999,'products/1/c_0022.jpg','2015-11-02',1,'5.1英寸全高清炫丽屏,2.5GHz四核处理器,1600万像素',0,'1'),('23','sonim XP7700 4G手机',1799,1699,'products/1/c_0023.jpg','2015-11-09',1,'三防智能手机 移动/联通双4G 安全 黑黄色 双4G美国军工IP69 30天长待机 3米防水防摔 北斗',0,'1'),('24','努比亚(nubia)Z9精英版 金色',3988,3888,'products/1/c_0024.jpg','2015-11-02',1,'移动联通电信4G手机 双卡双待真正的无边框!金色尊贵版!4GB+64GB大内存!',0,'1'),('25','Apple iPhone 6 Plus (A1524) 16GB 金色',5188,4988,'products/1/c_0025.jpg','2015-11-02',0,'Apple iPhone 6 Plus (A1524) 16GB 金色 移动联通电信4G手机 硬货 硬实力',0,'1'),('26','Apple iPhone 6s (A1700) 64G 玫瑰金色',6388,6088,'products/1/c_0026.jpg','2015-11-02',0,'Apple iPhone 6 Plus (A1524) 16GB 金色 移动联通电信4G手机 硬货 硬实力',0,'1'),('27','三星 Galaxy Note5(N9200)32G版',5588,5388,'products/1/c_0027.jpg','2015-11-02',0,'旗舰机型!5.7英寸大屏,4+32G内存!不一样的SPen更优化的浮窗指令!赠无线充电板!',0,'1'),('28','三星 Galaxy S6 Edge+(G9280)32G版 铂光金',5999,5888,'products/1/c_0028.jpg','2015-11-02',0,'赠移动电源+自拍杆+三星OTG金属U盘+无线充电器+透明保护壳',0,'1'),('29','LG G4(H818)陶瓷白 国际版',3018,2978,'products/1/c_0029.jpg','2015-11-02',0,'李敏镐代言,F1.8大光圈1600万后置摄像头,5.5英寸2K屏,3G+32G内存,LG年度旗舰机!',0,'1'),('3','华为荣耀6',1599,1499,'products/1/c_0003.jpg','2015-11-02',0,'荣耀 6 (H60-L01) 3GB内存标准版 黑色 移动4G手机',0,'1'),('30','微软(Microsoft) Lumia 640 LTE DS (RM-1113)',1099,999,'products/1/c_0030.jpg','2015-11-02',0,'微软首款双网双卡双4G手机,5.0英寸高清大屏,双网双卡双4G!',0,'1'),('31','宏碁(acer)ATC705-N50 台式电脑',2399,2299,'products/1/c_0031.jpg','2015-11-02',0,'爆款直降,满千减百,品质宏碁,特惠来袭,何必苦等11.11,早买早便宜!',0,'2'),('32','Apple MacBook Air MJVE2CH/A 13.3英寸',6788,6688,'products/1/c_0032.jpg','2015-11-02',0,'宽屏笔记本电脑 128GB 闪存',0,'2'),('33','联想(ThinkPad) 轻薄系列E450C(20EH0001CD)',4399,4199,'products/1/c_0033.jpg','2015-11-02',0,'联想(ThinkPad) 轻薄系列E450C(20EH0001CD)14英寸笔记本电脑(i5-4210U 4G 500G 2G独显 Win8.1)',0,'2'),('34','联想(Lenovo)小新V3000经典版',4599,4499,'products/1/c_0034.jpg','2015-11-02',0,'14英寸超薄笔记本电脑(i7-5500U 4G 500G+8G SSHD 2G独显 全高清屏)黑色满1000減100,狂减!火力全开,横扫3天!',0,'2'),('35','华硕(ASUS)经典系列R557LI',3799,3699,'products/1/c_0035.jpg','2015-11-02',0,'15.6英寸笔记本电脑(i5-5200U 4G 7200转500G 2G独显 D刻 蓝牙 Win8.1 黑色)',0,'2'),('36','华硕(ASUS)X450J 黑色独显',4599,4399,'products/1/c_0036.jpg','2015-11-02',0,'14英寸笔记本电脑 (i5-4200H 4G 1TB GT940M 2G独显 蓝牙4.0 D刻 Win8.1 黑色)',0,'2'),('37','戴尔(DELL)灵越',3399,3299,'products/1/c_0037.jpg','2015-11-03',0,' Ins14C-4528B 14英寸笔记本(i5-5200U 4G 500G GT820M 2G独显 Win8)黑',0,'2'),('38','惠普(HP)WASD 暗影精灵',5699,5499,'products/1/c_0038.jpg','2015-11-02',0,'15.6英寸游戏笔记本电脑(i5-6300HQ 4G 1TB+128G SSD GTX950M 4G独显 Win10)',0,'2'),('39','Apple 配备 Retina 显示屏的 MacBook',11299,10288,'products/1/c_0039.jpg','2015-11-02',0,'Pro MF840CH/A 13.3英寸宽屏笔记本电脑 256GB 闪存',0,'2'),('4','联想 P1',2199,1999,'products/1/c_0004.jpg','2015-11-02',0,'联想 P1 16G 伯爵金 移动联通4G手机充电5分钟,通话3小时!科技源于超越!品质源于沉淀!5000mAh大电池!高端商务佳配!',0,'1'),('40','机械革命(MECHREVO)MR X6S-M',6799,6599,'products/1/c_0040.jpg','2015-11-02',0,'15.6英寸游戏本(I7-4710MQ 8G 64GSSD+1T GTX960M 2G独显 IPS屏 WIN7)黑色',0,'2'),('41','神舟(HASEE) 战神K660D-i7D2',5699,5499,'products/1/c_0041.jpg','2015-11-02',0,'15.6英寸游戏本(i7-4710MQ 8G 1TB GTX960M 2G独显 1080P)黑色',0,'2'),('42','微星(MSI)GE62 2QC-264XCN',6199,5999,'products/1/c_0042.jpg','2015-11-02',0,'15.6英寸游戏笔记本电脑(i5-4210H 8G 1T GTX960MG DDR5 2G 背光键盘)黑色',0,'2'),('43','雷神(ThundeRobot)G150S',5699,5499,'products/1/c_0043.jpg','2015-11-02',0,'15.6英寸游戏本 ( i7-4710MQ 4G 500G GTX950M 2G独显 包无亮点全高清屏) 金',0,'2'),('44','惠普(HP)轻薄系列 HP',3199,3099,'products/1/c_0044.jpg','2015-11-02',0,'15-r239TX 15.6英寸笔记本电脑(i5-5200U 4G 500G GT820M 2G独显 win8.1)金属灰',0,'2'),('45','未来人类(Terrans Force)T5',10999,9899,'products/1/c_0045.jpg','2015-11-02',0,'15.6英寸游戏本(i7-5700HQ 16G 120G固态+1TB GTX970M 3G GDDR5独显)黑',0,'2'),('46','戴尔(DELL)Vostro 3800-R6308 台式电脑',3299,3199,'products/1/c_0046.jpg','2015-11-02',0,'(i3-4170 4G 500G DVD 三年上门服务 Win7)黑',0,'2'),('47','联想(Lenovo)H3050 台式电脑',5099,4899,'products/1/c_0047.jpg','2015-11-11',0,'(i5-4460 4G 500G GT720 1G独显 DVD 千兆网卡 Win10)23英寸',0,'2'),('48','Apple iPad mini 2 ME279CH/A',2088,1888,'products/1/c_0048.jpg','2015-11-02',0,'(配备 Retina 显示屏 7.9英寸 16G WLAN 机型 银色)',0,'2'),('49','小米(MI)7.9英寸平板',1399,1299,'products/1/c_0049.jpg','2015-11-02',0,'WIFI 64GB(NVIDIA Tegra K1 2.2GHz 2G 64G 2048*1536视网膜屏 800W)白色',0,'2'),('5','摩托罗拉 moto x(x+1)',1799,1699,'products/1/c_0005.jpg','2015-11-01',0,'摩托罗拉 moto x(x+1)(XT1085) 32GB 天然竹 全网通4G手机11月11天!MOTO X震撼特惠来袭!1699元!带你玩转黑科技!天然材质,原生流畅系统!',0,'1'),('50','Apple iPad Air 2 MGLW2CH/A',2399,2299,'products/1/c_0050.jpg','2015-11-12',0,'(9.7英寸 16G WLAN 机型 银色)',0,'2'),('6','魅族 MX5 16GB 银黑色',1899,1799,'products/1/c_0006.jpg','2015-11-02',0,'魅族 MX5 16GB 银黑色 移动联通双4G手机 双卡双待送原厂钢化膜+保护壳+耳机!5.5英寸大屏幕,3G运行内存,2070万+500万像素摄像头!长期省才是真的省!',0,'1'),('7','三星 Galaxy On7',1499,1398,'products/1/c_0007.jpg','2015-11-14',0,'三星 Galaxy On7(G6000)昂小七 金色 全网通4G手机 双卡双待新品火爆抢购中!京东尊享千元良机!5.5英寸高清大屏!1300+500W像素!评价赢30元话费券!',0,'1'),('8','NUU NU5',1288,1190,'products/1/c_0008.jpg','2015-11-02',0,'NUU NU5 16GB 移动联通双4G智能手机 双卡双待 晒单有礼 晨光金香港品牌 2.5D弧度前后钢化玻璃 随机附赠手机套+钢化贴膜 晒单送移动电源+蓝牙耳机',0,'1'),('9','乐视(Letv)乐1pro(X800)',2399,2299,'products/1/c_0009.jpg','2015-11-02',0,'乐视(Letv)乐1pro(X800)64GB 金色 移动联通4G手机 双卡双待乐视生态UI+5.5英寸2K屏+高通8核处理器+4GB运行内存+64GB存储+1300万摄像头!',0,'1');

        案例1-前台分类信息展示
        需求:
            访问任意页面的时候,都需要将分类的信息展示出来

        技术分析:

            静态包含
            ajax异步的数据交互

            要从redis中获取数据
                    有数据
                         直接返回
                    
                    无数据
                         从mysql中拿数据
                         放到redis中
                         然后返回

        实现步骤:
            1 抽取所有页面上 logo和菜单部分(head.jsp)
                页面加载的时候
                编写函数
                    发送ajax请求 $.post(url,params,fn,type);
                        url:/store/category
                        params: method=findAll
                        fn:将返回值遍历,每一个分类封装成li标签,插入到ul标签内部
                        type:json
                    编写categoryservlet,继承baseservlet,编写findAll方法
                        调用service,查询所有的分类,分类列表的json字符串(String)
                        写回页面
                    categoryservice中的操作
                        调用dao,获取所有的分类
                        将list转成json返回
            2 在所有的页面里将 head.jsp 包含进去
                获取返回值
                遍历返回值
                每一个分类封装成li标签,插入到ul标签内部
                
            3 使用redis进行优化(理解)
                修改service层的代码
                    获取的时候,去redis中获取,
                        若获取到了返回
                        若没有获取到,先去mysql数据库中查询出来,将list转成json放入redis中即可

        -----------------------------------------------------------------------------------------------------
        案例2-分类商品的分页展示
        需求:
            点击菜单栏上某一个分类的时候,将该分类下的商品,分页展示出来(默认第一页)

        技术分析:
            分页
                起始数据
                limit (当前页-1)*每页显示的条数,每页显示的条数


                (重要)页面上需要的数据(list)
                        当前页(pageNumber) 
                        每页显示的条数(pageSize) 
                
                
                总页数(totalPage)
                总记录数(totalCount)
                    总记录数%每页显示的条数==0
                        总页数=总记录数/每页显示的条数
                      
                 pageBean

        步骤分析:
            1.修改head.jsp上的每个分类的超链接
                <a href="/store/product?method=findByPage&pageNumber=1&cid=xxx">
            2.在cateservlet中编写findByPage方法
                获取pagenumber
                获取cid
                设置pageSize
                
                调用service获取分页的数据 返回值:PageBean
                
                将pagebean放入request域中,请求转发 /jsp/product_list.jsp
            3.编写service:
                返回值:pagebean
                创建一个pagebean
                
                设置当前页需要的数据
                    调用dao
                    
                设置总记录数
                    调用dao
            4.dao
            5.在jsp/product_list.jsp上展示商品

        -----------------------------------------------------------------------------------------------------

        案例3-单个商品详情

        需求:
            在首页上点击每个商品,将这个商品的详细信息展示在页面上(product_info.jsp)


        步骤分析:
            1.给每个商品添加超链接
                <a href="/store/product?method=getById&pid=xxx">yy</a>
            2
            .编写productservlet,继承baseservlet,编写getById
                获取商品的pid
                调用service获取一个商品 返回值:product
                请求转发到product_info.jsp
            
            3.service ,dao
            
            4.在product_info.jsp将商品展示

        ------------------------------------------------------------------------------------------------

        案例4-最新商品和热门商品展示
        需求:
            访问首页的时候,需要将最新商品和热门商品展示出来.

            is_hot:是否热门
            热门: 1 
            不热门:0

            pflag: 是否下架 (逻辑删除)
            没下架: 0
            下架了: 1

            查最新:   list =select * from product where pflag=0 order by date desc limit 0,9
            查热门:   list=SELECT * FROM product WHERE pflag=0 AND is_hot=1 ORDER BY pdate DESC LIMIT 0,9;
            
        步骤:
            
            1.访问项目首页,请求转发productServlet
                productServlet中处理
                    调用productservice查询热门商品和最新商品, 每一个都返回一个list
                    将两个list放入request域中,请求转发到 /jsp/index.jsp
            
            
            
            2.在页面上将数据遍历出来
        
                            商城案例实现
                        

今日内容 (购物车模块 订单模块)
     
     购物车
     
     生成订单

案例1-添加到购物车

需求:
    在商品的详情页面,输入购买数量,点击加入购物车,将该商品添加到购物车了

技术分析:

    一个用户只有一个购物车,购物车里面的商品都是用户临时选择的
    所以购物车的商品,我们并不会存在数据库中


    现实中:
    购物车--->存放商品

    在java代码中:
    javabean---->商品数据

    对等:
        Cart---->商品数据

购物车 -------------------------------------> Cart
    商品图片                {
    商品名称                    商品图片属性
    商品价格                    商品名称属性
    商品数量                    商品价格属性
    商品小计                    商品数量属性
                            商品的小计属性
    总金额                     
                            商品总金额的属性
                        }   
                                            
一个用户---存2个商品(大冬瓜,小冬瓜,黄瓜)-----> Cart
                      {
                        购物项对象的集合(3个购物项对象)

                        商品总金额的属性  
                      }

   购物项(多个)
    
    CartItem
        {
            商品图片属性
            商品名称属性
            商品价格属性
                ----替换成商品对象(好处:扩展性很强)
                
            商品数量属性
            商品的小计属性
        
        }

   购物车(1个)

    Cart
       {
        购物项集合(new CartItem)
        商品总金额的属性
       }

jack用户---大冬瓜----CartItem(商品对象,商品数量,商品小计 )
jack用户---小冬瓜----CartItem(商品对象,商品数量,商品小计 

----Cart(购物项集合,总金额)

任务:封装这2个对象

CartItem  
    商品对象--->pid编号
    商品数量--->购买数量
    商品小计---商品对象.getshop_price*数量
Cart
    购物项集合
    总金额(待定)

////////////////////////////////
案例2-从购物车移除一个商品
需求:
    在cart.jsp上,点击某一个商品的 删除 ,点击确定,从购物车中移除.
步骤分析:
    1.给 删除 添加连接
        /store/cart?method=remove&pid=xxx
    
    2.在cartservlet中编写remove方法
        获取pid
        获取cart,执行removeFromCart()方法
        重定向到cart.jsp

案例3-清空购物车
需求:
    点击cart.jsp上的 清空购物车,需要将购物车中所有商品移除掉

步骤分析:
    1.修改 清空购物车的连接
        /store/cart?method=clear
    2.编写clear方法
        获取购物车,执行clearCart()
        重定向到cart.jsp上
    3.判断购物车中是否有商品,  
        有则展示
        无则提示
/////////////////////////

案例2-生成订单
需求:
    在cart.jsp上,点击 "提交订单",将购物车中的商品,最终保存到数据库中.

技术分析:

    要把购物车的而所有数据在生成订单的时候,插入的数据库的2张表上

当用户开始点击生成订单的时候
        会产生1个订单以及N个订单下的订单商品


        1个订单详情  (订单编号,下单时间,订单总金额....)

        N个订单商品详情 (订单商品的数量 订单商品的时间,订单商品的id...)

    saveOrders(对象)
    订单表(orders)  
        订单ID:  UUID
        订单时间:  点击生成订单的当前系统时间
        总金额:  cart购物车对象中的总金额
        订单的状态: 0 未付款  1 已付款未发货  2 以发货未收货 3 以收货未评价  4 已结束

        地址
        姓名
        电话
            -------- 下订单的时候不写,在要付款的时候在填写

    saveOrderitem(对象)
    订单详情表(orderitem)
        订单详情ID: uuid
        订单ID:    订单表的主键
        商品ID:    商品表的主键
        数量:      购物项里的数量
        小计:      购物项里的小计

需要的表
    
    -- 订单表
    javabean=orders(封装订单时间,订单编号,订单总金额,订单状态,订单收货人,订单收货人电话...)
    dao:insert into orders values(orders.getoid,)

    CREATE TABLE `orders` (
          `oid` varchar(32) NOT NULL,
          `ordertime` date DEFAULT NULL,
          `total` double DEFAULT NULL,
          `state` int(11) DEFAULT NULL,
          `address` varchar(30) DEFAULT NULL,
          `name` varchar(20) DEFAULT NULL,
          `telephone` varchar(20) DEFAULT NULL,
          `uid` varchar(32) DEFAULT NULL,
          PRIMARY KEY (`oid`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    


    javabean==orderitem(封装所属订单,封装该订单项的数量,封装该订单项的小计..)
    dao:insert into orders values(orderitem.getitemid....)
    
    -- 订单商品详情表
        CREATE TABLE `orderitem` (
          `itemid` varchar(32) NOT NULL,
          `count` int(11) DEFAULT NULL,
          `subtotal` double DEFAULT NULL,
          `pid` varchar(32) DEFAULT NULL,  // 订单项下的商品
          `oid` varchar(32) DEFAULT NULL,  // 订单项所属的订单
          PRIMARY KEY (`itemid`),
          KEY `fk_0001` (`pid`),
          KEY `fk_0002` (`oid`),
          CONSTRAINT `fk_0001` FOREIGN KEY (`pid`) REFERENCES `product` (`pid`),
          CONSTRAINT `fk_0002` FOREIGN KEY (`oid`) REFERENCES `orders` (`oid`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;   
                        
                    商城案例实现

今日内容:
    我的订单(难点)
    单个订单详情
    在线支付(第三方的支付平台--易宝(了解))
    权限过滤器
//////////////////////////////////////////
案例1-我的订单
需求:
    在任意页面上,点击 "我的订单" 将当前用户的订单(包含订单项列表)分页展示出来

技术分析:
      
      分页
      多表查询

步骤分析:
    1.修改 head.jsp 上"我的订单"的连接
        /store/order?method=MyOrder&pageNumber=1
    2.在orderservlet中编写 MyOrder
        获取pagenumber 设置pagesize 获取当前用户的id
        调用service完成分页查询操作:返回pagebean
        将pagebean放入request域中,请求转发 order_list.jsp
    3.service中操作
        创建pagebean
        设置总条数
        设置当前页数据
    4.dao中操作:
        获取当前页订单数据
            sql:只能查询订单的基本信息,没有订单项
                select * from orders where uid = ? order by ordertime desc limit ?,?
                 
            执行上面的sql,返回的 List<Order>
            遍历orderlist集合,获取到每一个订单,关联查询订单项和商品表,将该订单下的所有信息查询出来,
                封装成orderItem,将每一个orderitem放入当前order的订单项列表中
                SELECT * FROM orderitem oi,product p WHERE oi.pid = p.pid AND oi.oid = '8727C1B22C214E6D865ECFB3B118E330'
                  
            上面的结果用什么封装???
                使用maplisthandler封装, 将查询结果的每一条记录封装成map 
                    (key:字段名(和bean属性名一样),value:具体指),将所有的map放入list中返回
                遍历map的list,获取每一个订单的详情,使用beanutils进行封装即可 封装orderitem和product对象,最后将orderitem对象放入订单项列表中
                [{itemid=xxxx,pname=华为,...},{itemid=uyyyyx,pname=中兴,...}]

---------------------------------------------------------------------------------------------------         

案例2-订单详情
需求:
    在订单列表页面上点击 "去付款",展示出当前的订单的详情.
步骤分析:
    1.修改 "去付款" 连接
        /store/order?method=payOrderPage&oid=xxxx
    2.在orderservlet编写payOrderPage方法
        获取oid
        调用service查询单个订单 返回值:order
        将order放入request域中,请求转发到order_info.jsp
    
    3.service中操作
    
    4.dao中操作
        先查询订单信息
            select * from orders where oid = ?
        
        再查询当前订单的订单项
            select * from orderitem oi,product p where oi.pid = p.pid and oi.oid=?
            使用maplisthandler进行封装
                获取每一个订单项详情,封装成orderitem,最后将orderitem添加到订单的订单项列表项即可
                
---------------------------------------------------------------------------------------------------
案例3-在线支付
需求:
    在详情页面上 输入收货人信息,选择支付的银行,点击确认订单,保存收获人信息,跳转到银行页面,输入用户名(卡号),点击支付,
    最后跳转到商城,提示 订单支付成功,(修改订单的状态)
技术分析:
    在线支付
/////////////////////
在线支付:
    对银行
    对第三方
    
/////////////////////////////////
支付步骤的分析:
    1.在订单详情页面上 填写收货人信息, 选择支付银行,点击"确认订单",向商城发送请求
        表单提交
            收货人信息
            支付银行
            订单号
        路径: /store/order?method=payorder
    
    2.在orderservlet中 编写pay方法
        接受收货人信息 订单号
        调用service获取订单,
            设置收货人信息
        更新订单
        
        拼接重定向的字符串

支付成功之后的步骤分析:
    编写callback方法
        获取第三方发送过来的数据(order_id)
        
        通过id获取订单
        修改订单的状态 =1
        更新订单
        
---------------------------------------------------------------------------------------------

案例4-权限过滤
需求:
    访问购物车的时候,需要判断用户是否登录,若没有登录,则提示
技术分析:
    过滤器
过滤器编写步骤:
    1.编写一个类 PrivilegeFilter 
        实现filter接口
        重写方法(主要doFilter)
    2.编写配置文件
        filter
        filter-mapping
步骤分析:
    doFilter方法中的逻辑
        从session中获取用户,
            判断用户是否为空
                若为空:提示"请先登录",请求转发到 /jsp/msg.jsp return
    
/////////////////////////////////////////////////
                            
                        商城案例的后台实现


回顾: jquery easyUi
        

作用:增强用户界面,完成了与服务器数据交互(异步方式)的功能


环境搭建:
        3个css文件+2个js文件

            easyui.css + images图片  themes/bootstrap/easyui.css + images图片
            
            icon.css+icons图标图片  themes/incos(incos.css)

            demo.css    demo/demo.css   

            js库
            jquery.easyui.min.js  jquery-easyui-1.4.2/(jquery.easyui.min.js/jquery.min.js) 



如果将一个普通的html标签渲染成easyui插件?  如果给这个插件设置属性,事件,方法?

例如:
    ps : add('abc');
        不加单引号仅限于数值类型
        如果涉及到了字符串类型就必须得加单引号,如果不加,它会认为是一个变量

静态方式/css方式
        特点: 都在标签体内设置

        <div class="easyui-dialog" data-options="属性,事件,方法"></div>
                    就是在标签体内通过属性class的值 easyui-组件名来渲染

                    就是标签体内通过属性data-options来设置该插件的属性,事件和方法

动态方式/js方式
        特点: 需要写js代码

        <div id="d"></div>

        <script>
                // 将html标签渲染成easy组件并设置属性
                $("标签体").组件名(
                    {
                        属性名1:属性值1,
                        属性名2:属性值2,
                        属性名3:属性值3
                    }
                )
                
                // 将html标签渲染成easy组件并设置事件
                $("标签体").组件名(
                    {
                        事件名1:function(){},
                        事件名2:function(){},
                        事件名3:function(){},
                    }
                )

                // 将html标签渲染成easy组件并设置方法
                $("标签体").组件名("该组件提供的方法名","方法参数")
                        方法参数有2种:
                            1 一个值: 直接写
                            2 多个值: 
                                  {
                                    值名1:值1,
                                    值名2:值2,
                                    值名2:值2
                                  }
        </script>

datagrid-data1.json
    {"total":28,"rows":[
    {"productid":"FI-SW-01","productname":"Koi","unitcost":10.00,"status":"P","listprice":36.50,"attr1":"Large","itemid":"EST-1"},
    {"productid":"K9-DL-01","productname":"Dalmation","unitcost":12.00,"status":"P","listprice":18.50,"attr1":"Spotted Adult Female","itemid":"EST-10"},
    {"productid":"RP-SN-01","productname":"Rattlesnake","unitcost":12.00,"status":"P","listprice":38.50,"attr1":"Venomless","itemid":"EST-11"},
    {"productid":"RP-SN-01","productname":"Rattlesnake","unitcost":12.00,"status":"P","listprice":26.50,"attr1":"Rattleless","itemid":"EST-12"},
    {"productid":"RP-LI-02","productname":"Iguana","unitcost":12.00,"status":"P","listprice":35.50,"attr1":"Green Adult","itemid":"EST-13"},
    {"productid":"FL-DSH-01","productname":"Manx","unitcost":12.00,"status":"P","listprice":158.50,"attr1":"Tailless","itemid":"EST-14"},
    {"productid":"FL-DSH-01","productname":"Manx","unitcost":12.00,"status":"P","listprice":83.50,"attr1":"With tail","itemid":"EST-15"},
    {"productid":"FL-DLH-02","productname":"Persian","unitcost":12.00,"status":"P","listprice":23.50,"attr1":"Adult Female","itemid":"EST-16"},
    {"productid":"FL-DLH-02","productname":"Persian","unitcost":12.00,"status":"P","listprice":89.50,"attr1":"Adult Male","itemid":"EST-17"},
    {"productid":"AV-CB-01","productname":"Amazon Parrot","unitcost":92.00,"status":"P","listprice":63.50,"attr1":"Adult Male","itemid":"EST-18"}
]}

这个文件表示要给esayui返回的分页数据
    
    EasyUI底层是用ajax做的,所以给easyUI回传的时候,必须使用json回传,也只能用json回传数据,(ajax回传就是用json传输数据的.)
                    商城案例的实现

上传原理解释:
    下面是请求体:
    ----------------------7e111423100812                                    ----->传统的方式
    Content-Disposition:form-data:name="username"                           整个请求体的内容="request.getInputStream()";
    lisi                                                                        
    ----------------------7e111423100812                                    实现步骤:
    Content-Disposition:form-data:name="upload";filename="cs.txt"               1:根据分割线将整个请求体的内容分成多个.
    Content-Type:text/plain                                                     2:根据filename判断哪些是普通表单项,哪些是上传表单项
    aaa                                                                         3.普通表单项:name和value              
    bbbb                                                                        4.上传表单项:表单项和表单内容
    cccccc                                                                                  io -- >服务器
                                                                                                |
上传:                                                                                         |
    浏览器端有3个要求                                                                       apache:上传工具包(企业开发)
        
        1 form表单的提交方式必须得是post    method=post

        2 上传框必须得有name属性 <input type="file" name="upload" />

        3 表单的enctype属性必须得是 multpart/form-data
        
                    在form表单里面有一个默认属性enctype,这个默认属性的默认属性值: enctype="application/x-www-form-urlencoded"
                                            url表单

                    只要玩上传,这个enctype属性值就必须修改了
                                enctype=multipart/form-data
                                            
                                            多部分表单

                    ps:上传就必须得是多部分表单

                    什么是url表单?
                            就是之前一直玩的
                            所有的内容都在请求体里面,以url形式进行参数的拼接
                                username=zhangsan&upload=cs.txt&password=123

                    什么是多部分表单?
                            所有的内容也都在请求体里面,但是以一部分一部分进行拼接的

                            -----------------------
                                    一部分
                            -------------------------
                                    一部分
                            ---------------------------
                                    一部分
                            .............

        服务器的要求:
            如果表单是以多部分进行提交的,那么request的3中获取数据的方法全部失效

上传:

    浏览器对于上传会要求3件事:
            
            1 上传框要有name属性  name="upload" 

            2 表单的method必须是post   method="post"

            3 表单的enctype属性必须得是 multipart/form-data
                    在表单里面有个entype属性,这个属性有一个默认值: 你写或则不写都会有
                        enctype="application/x-www-form-urlencoded"(这个属性表示告诉服务器给你上传所有提交的内容都是字符串,没有二进制的形式)      url表单
                        
                    
                     从要玩上传开始,这个属性就必须要做更改,要把这个属性改成:
                         enctype="multipart/form-data"(该属性以后文件是以二进制形式传输的)           多部分表单
        
            什么是url(普通)表单? 什么是多部分表单?

                
                url(普通)表单: 就是之前一直玩的
                    username=zhangsan&password=123&hobby=eat&hobby=sleep..  以url形式进行数据拼装传递的表单
                
                多部分表单:
                        
                    ---------------------------------------
                    一部分

                    -----------------------------------------
                    一部分

                    -------------------------------------------
                    一部分

            
            不论是url(普通)表单还是多部分表单,数据都在请求体
                        

            注意:如果是多部分的表单进行提交,之前使用的request获取数据的3种方式,全部失效

部署应用

需求:
    将我们自己的项目部署到linux下

技术分析:
    
       1 linux的环境
            安装jdk
            安装tomcat
            安装mysql
                安装redis

       
       2 如何把已完成的项目给linux
            
            项目打包:   后缀名: .war
                通过ide工具: 在项目右键-->export-->搜索 war -->选择目的地
                特点:在web服务器下的webapps目录下,随着服务器的启动而解压      
                
       
       
       3 如何把数据库表和数据给linux
             数据备份还原:
                
                数据备份 导出本地数据库中的表结构和数据

                数据迁移 导入表结构和数据到linux下的数据库

注意:
    中文乱码
        在连接的url后面追加:
            ?useUnicode=true&characterEncoding=utf-8
    
        重启tomcat

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容