IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 2022年5月7号博客内容SSM框架项目管理-------------超市管理系统(第十二课针对订单管理普通的用户增加一条数据的记录) -> 正文阅读

[系统运维]2022年5月7号博客内容SSM框架项目管理-------------超市管理系统(第十二课针对订单管理普通的用户增加一条数据的记录)

2022年5月7号博客内容SSM框架项目管理-------------超市管理系统(第十二课针对订单管理普通的用户增加一条数据的记录)

思路分析:过些时间会写几篇关于数据库的多表联查。

提出一个问题:如何从浏览器中增加一条数据的同时保证数据库里面的数据也能增加?这里还是MVC三层架构的思想.访问流程图我不在介绍了.写了这么多流程应该在自己的脑子里吧!
来理清一下解题的思路:
角色:普通用户。
第一步:当用户点增加数据的按钮可以肯定的是一定有要跳转的页面,而这个页面一定是跳到控制器,控制器定义方法,用于标获得要增加的订单信息。
第二步:数据增加完成后数据后一定会跳转到一个独立增加数据的页面。在这个页面中一定会有跳转到控制器,并且带上增加好的的数据跳到控制器 .而这个控制器中一定接收浏览器转送到了服务器。
第三步:控制器定义方法用于接收浏览器发到控制器增加的数据,然后利用list中调用Map集合的方式将数据,层层发送最终到数据库中增加数据,并且将增加后的数据库刷新将结果返回给控制器,然后跳转制页面进行刷新。
第四步:分析三层 控制层???? 数据访问层
第五步业务逻辑层分析。
第六步代码实操一步一步的操作。

?重点在第五步业务逻辑层的分析。上面是我要增加一条数据的详细信息。

不要将数据的增加那么简单关于用户的增加我们老师讲了一上午呢!我还是没有明白。

针对逻辑层的步步分析观察下面的Mysql语句图片。

功能:自动生成账单编号
需求分析:
1.当订单表中不存在今年年份的订单时,那么当前添加订单的订单编号就应该为BILL今年的年份_001
2.当订单表中存在今年的订单时,从订单表中找出今年的订单的最近添加的订单,最后一个添加的订单
然后在该订单的尾号加一,获得的就是我们添加订单的订单编号
代码实现思路:
1.将订单表中所有订单按订单编号进行降序排列(从大到小排列),取第一条数据,得到的就是整个订单表中最新的订单编号
select billCode from smbms_bill order by billCode desc LIMIT 0,1
2.使用java代码获得今年的年份? 2022
3.将最新的订单编号进行按“_”进行分割 BILL2022_003? 分割成两部分BILL2022????? 003
4.取分割后的第一部分进行截取出年份
5.然后将截取出来的年份与今年的年份进行比较,如果不相等,说明整个订单表中不存在今年的年份
那么我们添加的订单BILL今年的年份_001
6.如果相等,说明订单表中存在今年的年份,取分割后的第二部分,先进行将字符串格式转换成int格式
7.然后进行加一
8.将加一之后的数字进行判断,是否小于10,前面补两个零,是否小于100,前面补一个零,是否小于1000,不需要补零。


分析完成先定义一个页面:用于增加数据的内容。

<%@page import="java.util.List" %>
<%@ page import="java.util.Map" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>超市订单管理系统--添加订单</title>
    <style>
        *{
            font-family: 楷体;
            font-size: 20px;
            background-color: #FFF2EF;
        }
        input{
            background: linear-gradient(100deg,black,black);
            color: red;
            border-radius: 12px;
        }

    </style>
</head>
<body>
<% List<Map<String, Object>> oList = (List<Map<String, Object>>) request.getAttribute("providers"); %>
<div style="width: 1200px;height: 800px;margin: auto;">
    <div style="width: 100%;height: 160px;">
        <div style="width: 100%;height: 20px;">

            <div align="left" style="width: 20%;height: 100%;float: left;">
                &nbsp;<a href="home.do" style="text-decoration: none;">返回首页</a>
            </div>

            <div align="right" style="width: 80%;height: 100%;float: right;">
                <a>欢迎,<span style="color: red;">${userInfo.userName}</span></a>
                &nbsp;&nbsp;<a href="index.do" style="text-decoration: none;">注销</a>&nbsp;
            </div>

        </div>
        <div align="center" style="width: 100%;height: 140px;line-height: 140px;"><h1>超市订单管理系统</h1></div>
    </div>
    <div align="center" style="width: 100%;height: 640px;">
        <form action="AddBill.do" method="post">
            <div style="padding: 5px 0px">
                <label for="productName">商品名称:</label>&nbsp;
                <input id="productName" name="productName" type="text" placeholder="请输入商品名称"/>
            </div>
            <div style="padding: 5px 0px">
                <label>商品描述:</label>
                <input type="text" name="productDesc" placeholder="请输入商品描述信息"></input>
            </div>
            <div style="padding: 5px 0px">
                <label>商品数量:</label>&nbsp;
                <input type="number" name="productCount" placeholder="请输入商品数量">
            </div>
            <div style="padding: 5px 0px">
                <label>商品单位:</label>&nbsp;
                <input type="text" name="productUnit" placeholder="请输入商品单位">
            </div>
            <div style="padding: 5px 0px">
                <label>商品总额:</label>&nbsp;
                <input type="number" name="totalPrice" placeholder="请输入商品总额">
            </div>
            <div style="padding: 5px 0px">
                <label>供应商名称:</label>&nbsp;
                <!-- Html5 新增的表单的新用法 -->
                <input type="search" name="proName" placeholder="请输入供应商名称" list="list">
                <datalist id="list">
                    <%
                        for (int i = 0; i < oList.size(); i++) {
                    %>
                    <option><%=oList.get(i).get("proName") %>
                    </option>
                    <%}%>
                </datalist>
                <%-- <select name="proName">
                    <%
                        for(int i=0;i<oList.size();i++){
                    %>
                    <option><%=oList.get(i).getProName() %></option>
                    <%} %>
                </select> --%>
            </div>
            <div style="padding: 5px 0px">
                <input type="submit"
                       value="添加"
                       style="width: 120px;background-color: green;
					 border: none;padding: 5px;border-radius: 5px;
					 color: white;"/>
            </div>
        </form>


    </div>
</div>
</body>
</html>

代码实操。

<div align="left" style="height: 40px;" >
				<a href="toAddBill.do" style="text-decoration: none;
				 text-align:center;  width: 50px;
				 height: 20px;
				 color: black;
				 font-size: 20px;
				 font-weight: bold;
				 margin-top:20px;margin-left:10px;
				 border-radius: 5px;">添加订单</a>
			</div>

第一步:当用户点增加数据的按钮可以肯定的是一定有要跳转的页面,而这个页面一定是跳到控制器,控制器定义方法,获得要增加的订单信息。

 @RequestMapping("/toAddBill.do")
  //将业务逻辑层对象自动写入进来
    @Autowired
    IBillService bService;
    //注入 IProviderService pService
    @Autowired
    IProviderService pService;
    List<Map<String, Object>> billls = null;


//定义方法用于增加订单页面 可以增加到页面展示信息
    @RequestMapping("/toAddBill.do")
    public ModelAndView toAddBill() {
        //跳转到增加页面之前,需要获得所有供应商的信息获得
        //并发送增加页面,共普通员工使用
        //调用之前的页面使用
        List<Map<String, Object>> providers = pService.getProviders();
        ModelAndView mav = new ModelAndView();
        mav.addObject("providers", providers);
        mav.setViewName("addBill");
        return mav;

    }


当我增加下面的信息是点击提交会跳到?

<form action="AddBill.do" method="post"> 在控制器中定义方法用于接收浏览器的数据

//定义方法,接收添加订单页面发送过来的订单信息
    @RequestMapping(value = "/AddBill.do",
            params = {"productName","productDesc","productCount","productUnit","totalPrice","proName"})
  public String AddBill(String productName,String productDesc,double productCount,String productUnit,
                          double totalPrice,String proName,HttpSession session){
  //定义Map集合,将数据进行封装,便于传输
        Map<String,Object> map=new HashMap<>();
        map.put("productName",productName);//商品名称
        map.put("productDesc",productDesc);//商品描述
        map.put("productCount",productCount);//商品数量
        map.put("productUnit",productUnit);//商品单位
        map.put("totalPrice",totalPrice);//总金额
        map.put("proName",proName);//供应商名称




 //获得登录系统的普通员工的id
        map.put("createdBy",((Map<String,Object>)session.getAttribute("userInfo")).get("id"));
        //保存添加订单的实时时间
        map.put("creationDate",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        //要存储的是供应商的id,把供应商的名称作为条件查询供应商表获得出对应的供应商id

上面的信息没有问题;关键在于

@1billCode:账单编号,自动生成账单编号
@2获得登录系统的普通员工的id

在业务逻辑层中解决@1billCode:账单编号,自动生成账单编号 问题。

//添加订单
    int addBill(Map<String,Object> map);

功能:自动生成账单编号
需求分析:
1.当订单表中不存在今年年份的订单时,那么当前添加订单的订单编号就应该为BILL今年的年份_001
2.当订单表中存在今年的订单时,从订单表中找出今年的订单的最近添加的订单,最后一个添加的订单
然后在该订单的尾号加一,获得的就是我们添加订单的订单编号
代码实现思路:
1.将订单表中所有订单按订单编号进行降序排列(从大到小排列),取第一条数据,得到的就是整个订单表中最新的订单编号
select billCode from smbms_bill order by billCode desc LIMIT 0,1
2.使用java代码获得今年的年份? 2022
3.将最新的订单编号进行按“_”进行分割 BILL2022_003? 分割成两部分BILL2022????? 003
4.取分割后的第一部分进行截取出年份
5.然后将截取出来的年份与今年的年份进行比较,如果不相等,说明整个订单表中不存在今年的年份
那么我们添加的订单BILL今年的年份_001
6.如果相等,说明订单表中存在今年的年份,取分割后的第二部分,先进行将字符串格式转换成int格式
7.然后进行加一
8.将加一之后的数字进行判断,是否小于10,前面补两个零,是否小于100,前面补一个零,是否小于1000,不需要补零。


更据老师提供的思路步步实操.


 @Override
    public int addBill(Map<String, Object> map) {
        map.put("billCode",getBillCode());
 public String getBillCode(){
 //将订单表中所有订单按订单编号进行降序排列(从大到小排列),取第一条数据,得到的就是整个订单表中最新的订单编号
        String order = dao.getOrder();
 //将所有订单信息按订单编号做降序排列,取第一条数据
    @Select("select billCode from smbms_bill order by billCode desc LIMIT 0,1")
    String getOrder();

这里你也可以用Mysql函数Max后去第一条数据或者是最后一条数据。

获取今年的年份

 String year = new SimpleDateFormat("yyyy").format(new Date());

将字符切割

?
 String[] s = order.split("_");

?
  String substring = s[0].substring(4);

取出第一部分判断

  if (!substring.equals(year)){
            //如果不相等,说明订单表中不存在今年的订单
            billCode="BILL"+year+"_001";
        }else {
            //订单表中存在今年的年份,取分割后的第二部分,先进行将字符串格式转换成int格式
            int number = Integer.parseInt(s[1]);
            //然后进行加一
            int newNumber=++number;
            billCode="BILL"+year+"_"+zero(newNumber);
        }
        return billCode;
    }
 public String zero(int newNumber){
        String n="";
        if (newNumber<10){
            n="00"+newNumber;
        }else if (newNumber<100){
            n="0"+newNumber;
        }else if (newNumber<1000){
            n=""+newNumber;
        }
        return n;
    }

在数据访问层解决:proName供应商的名称 涉及到mysql子查询.

//添加订单
    @Insert("insert into smbms_bill(smbms_bill.billCode,smbms_bill.productName," +
            "smbms_bill.productDesc,smbms_bill.productUnit,smbms_bill.productCount," +
            "smbms_bill.totalPrice,smbms_bill.createdBy,smbms_bill.creationDate," +
            "smbms_bill.providerId)  " +
            "values(#{billCode},#{productName},#{productDesc},#{productUnit}," +
            "#{productCount},#{totalPrice},#{createdBy},#{creationDate}," +
            "(select id from smbms_provider where smbms_provider.proName=#{proName}))")
    
int addBill(Map<String, Object> map);
package com.smbms.service;

import com.smbms.dao.IBillDao;

import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

//窗口Service层对象
@Service(value = "bService")
public class BillServiceImp implements IBillService {
    @Autowired
    IBillDao dao;


    @Override
    public List<Map<String, Object>> getBillsByUserId(long userId) {
        //第一点 错误 return dao.getBillsById(Id);
        return dao.getBillsById(userId);
    }

    @Override
    public List<Map<String, Object>> getBills() {
        return dao.getBills();
    }

    @Override
    public int updateBill(Map<String, Object> map) {


        return dao.updateBill(map);
    }

    @Override
    public int delBill(long id) {
        return dao.delBill(id);
    }


    @Override
    public int updatePay(long billId) {
        return dao.updatePay(billId);
    }

    @Override
    public int addBill(Map<String, Object> map) {
        map.put("billCode",getBillCode());
        return dao.addBill(map);
    }



   
    public String getBillCode(){
        String billCode="";
        //将订单表中所有订单按订单编号进行降序排列(从大到小排列),取第一条数据,得到的就是整个订单表中最新的订单编号
        String order = dao.getOrder();
        //使用java代码获得今年的年份
        String year = new SimpleDateFormat("yyyy").format(new Date());
        //将最新的订单编号进行按“_”进行分割
        String[] s = order.split("_");
        //取分割后的第一部分进行截取出年份
        String substring = s[0].substring(4);
        //将截取出来的年份与今年的年份进行比较
        if (!substring.equals(year)){
            //如果不相等,说明订单表中不存在今年的订单
            billCode="BILL"+year+"_001";
        }else {
            //订单表中存在今年的年份,取分割后的第二部分,先进行将字符串格式转换成int格式
            int number = Integer.parseInt(s[1]);
            //然后进行加一
            int newNumber=++number;
            billCode="BILL"+year+"_"+zero(newNumber);
        }
        return billCode;
    }
    //数字进行判断,是否小于10,前面补两个零,是否小于100,前面补一个零,是否小于1000,不需要补零
    public String zero(int newNumber){
        String n="";
        if (newNumber<10){
            n="00"+newNumber;
        }else if (newNumber<100){
            n="0"+newNumber;
        }else if (newNumber<1000){
            n=""+newNumber;
        }
        return n;
    }

}
package com.smbms.service;

import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface IBillService {

    //将用户id作为条件,查询该用户的所有订单
    //将用户id作为条件,查询该用户的所有订单
    List<Map<String, Object>> getBillsByUserId(long userId);


    //将订单id作为修改条件,将未支付字段改为已支付
    int updatePay(long id);


    //获得所有订单信息
    List<Map<String, Object>> getBills();



    //添加订单
    int addBill(Map<String,Object> map);


    //修改
    int updateBill(Map<String,Object> map);



    int delBill( long id);




}
package com.smbms.controller;


import com.smbms.entity.Tb_User;
import com.smbms.service.IBillService;
import com.smbms.service.IProviderService;
import com.smbms.utils.SMBMSUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 */
@Controller
public class BillControllerImp implements IBillController {
    //将业务逻辑层对象自动写入进来
    @Autowired
    IBillService bService;
    //注入 IProviderService pService
    @Autowired
    IProviderService pService;
    List<Map<String, Object>> billls = null;


    //定义方法,用于普通员工进入订单管理查看自身的订单信息,
    // 以及添加订单信息
    @RequestMapping("/GetBillsByUserId.do")
    public ModelAndView GetBillsByUserId(HttpSession session) {
        //需要从session中获得登录成功之后保存的用户id作为查询数据库的条件
//        Tb_User user= (Tb_User) session.getAttribute("user");
//        long id=user.getId();
        Map<String, Object> map = (Map<String, Object>) session.getAttribute("userInfo");
        long userId = (long) map.get("id");
        List<Map<String, Object>> billsByUserId = bService.getBillsByUserId(userId);
        ModelAndView mav = new ModelAndView();
        mav.addObject("bills", billsByUserId);
        mav.setViewName("billList");
        return mav;
    }



    //用于UpdatePayBill.do 修改支付功能
    @RequestMapping("/UpdatePayBill.do")
    public String UpdatePayBill(@RequestParam long id) {

        //更据定单id完成修改功能
        int i = bService.updatePay(id);
        String url = null;
        if (i > 0) {
            url = "redirect:GetBillsByUserId.do";
        }

        return url;
    }


    //第二种身份获得的方案
    @RequestMapping("/GetBills.do")
    public ModelAndView GetBills() {
        ModelAndView mav = new ModelAndView();
        billls = bService.getBills();
        mav.addObject("bills", billls);
        mav.setViewName("billList2");

        return mav;
    }


    //定义方法用于增加订单页面 可以增加到页面展示信息
    @RequestMapping("/toAddBill.do")
    public ModelAndView toAddBill() {
        //跳转到增加页面之前,需要获得所有供应商的信息获得
        //并发送增加页面,共普通员工使用
        //调用之前的页面使用
        List<Map<String, Object>> providers = pService.getProviders();
        ModelAndView mav = new ModelAndView();
        mav.addObject("providers", providers);
        mav.setViewName("addBill");
        return mav;

    }


    //定义方法,接收添加订单页面发送过来的订单信息
    @RequestMapping(value = "/AddBill.do",
            params = {"productName","productDesc","productCount","productUnit","totalPrice","proName"})
    public String AddBill(String productName,String productDesc,double productCount,String productUnit,
                          double totalPrice,String proName,HttpSession session){
        //定义Map集合,将数据进行封装,便于传输
        Map<String,Object> map=new HashMap<>();
        map.put("productName",productName);//商品名称
        map.put("productDesc",productDesc);//商品描述
        map.put("productCount",productCount);//商品数量
        map.put("productUnit",productUnit);//商品单位
        map.put("totalPrice",totalPrice);//总金额
        map.put("proName",proName);//供应商名称
        //billCode:账单编号,自动生成账单编号
        //获得登录系统的普通员工的id
        map.put("createdBy",((Map<String,Object>)session.getAttribute("userInfo")).get("id"));
        //保存添加订单的实时时间
        map.put("creationDate",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        //要存储的是供应商的id,把供应商的名称作为条件查询供应商表获得出对应的供应商id
        int i = bService.addBill(map);
        String url="";
        if (i>0)
            //添加成功,刷新页面
            System.out.println("增加了一条订单管理信息");
            url="redirect:GetBillsByUserId.do";
        return url;
    }


    //定义方法,用于接收下标,根据下标获得要修改的订单信息
    @RequestMapping("/GetBillByIndex.do")

    public ModelAndView GetBillByIndex(@RequestParam int index){
        Map<String, Object> map = billls.get(index);
        //拿到所有供应商的名称给经理进行选择
        List<Map<String, Object>> providers = pService.getProviders();
        ModelAndView mav=new ModelAndView();
        mav.addObject("providers",providers);
        mav.addObject("bill",map);
        mav.setViewName("updateBill");
        return mav;
    }

//
    @RequestMapping(value = "/updateBill.do",params =
            {"id","productName","productDesc","productCount","productUnit","totalPrice","isPayment","proName"})
    public  String updateBill(long id,String productName,String productDesc,double productCount,String productUnit,
                              double totalPrice,int isPayment,String proName ,HttpSession session){
        Map<String,Object> map=new HashMap<>();
        map.put("id",id);
        map.put("productName",productName);//商品名称
        map.put("productDesc",productDesc);//商品描述
        map.put("productCount",productCount);//商品数量
        map.put("productUnit",productUnit);//商品单位
        map.put("totalPrice",totalPrice);//总金额
        map.put("isPayment",isPayment);
        map.put("proName",proName);//供应商名称
        //经理的id
        map.put("modifyBy",((Map<String,Object>)session.getAttribute("userInfo")).get("id"));
        //修改订单的实时时间
        map.put("modifyDate",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        System.out.println("获得的数据为"+map);
        int i = bService.updateBill(map);
        String url="";
        if (i>0)
            //修改订单成功,刷新订单列表页面
            System.out.println("修改了一条订单管理信息");
            url="redirect:GetBills.do";
        return url;
    }


    //删除订单经理
    @RequestMapping("/DeleteBill.do")
    public  String DeleteBill(@RequestParam long id){
        int i = bService.delBill(id);
        String url=" ";
        if(i>0){
            System.out.println("删除了一条订单光管理的信息");
            url="redirect:GetBills.do";
        }
        return url;
    }
}

运行结果图:

?

?

这个项目到今天结束后期会自己定义项目的Sql语句项目访问模块对数据的增删改查对数据的操作.在这个项目中老师将前端页面发给了我们。我们只是跟着老师走了一遍流程。其实自己还是不会,正因为又不会的所以才不断的区学习。其实主要的功能又是对数据的增删改查。更据自己学习的广度和深度可以对页面进行修改。在日后的工作中会出现多表联查。在现实世界中你浏览的任何页面都是对数据的增删改查操作的.后期会对SSM框架进行回顾.温故而知新,可以为师矣。这又是学习的过程。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 13:09:20  更:2022-05-09 13:12:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 18:32:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码