基于javaweb和mysql的jsp+servlet会议室管理系统(java+jsp+html+servlet+mysql)

私信源码获取及调试交流

私信源码获取及调试交流

运行环境

Java≥8、MySQL≥5.7、Tomcat≥8

开发工具

eclipse/idea/myeclipse/sts等均可配置运行

适用

课程设计,大作业,毕业设计,项目练习,学习演示等

功能说明

基于javaweb的JSP+Servlet会议室管理系统(java+jsp+html+servlet+mysql)

项目介绍

本项目包含两个角色,管理员与用户角色;

管理员角色包含以下功能: 查看预订,查看会议,部门管理,员工注册,添加会议室,审批员工等功能。

用户角色包含以下功能: 预定会议,查看我将参加的会议,会议室查看,通知信息查看,查看撤销会议等功能。

环境需要

1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可 4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本; 6.是否Maven项目:否;

技术栈

JSP+CSS+JavaScript+html+mysql+servlet

使用说明

  1. 使用Navicat或者其它工具,在mysql中创建对应名称的数据库,并导入项目的sql文件; 2. 使用IDEA/Eclipse/MyEclipse导入项目,Eclipse/MyEclipse导入时,若为maven项目请选择maven; 若为maven项目,导入成功后请执行maven clean;maven install命令,然后运行; 3. 将项目中dao/DBUtils.java配置文件中的数据库配置改为自己的配置; 4. 运行项目,输入localhost:8080/meeting/ 注:Tomcat中配置路径必须为meeting,否则会有异常; 管理员账号/密码:admin/admin 用户账号/密码:linyaokun/123456
        int totalPage = totalCount / Integer.parseInt(count) + 1;
        req.setAttribute("list", list);
        req.setAttribute("totalCount", totalCount);
        req.setAttribute("totalPage", totalPage);
        req.setAttribute("page", page);
        req.setAttribute("meetingname", meetingname);
        req.setAttribute("roomname", roomname);
        req.setAttribute("reservername", reservername);
        req.setAttribute("reservefromdate", reservefromdate);
        req.setAttribute("reservetodate", reservetodate);
        req.setAttribute("meetingfromdate", meetingfromdate);
        req.setAttribute("meetingtodate", meetingtodate);
        req.setAttribute("count", count);
        req.getRequestDispatcher("/searchmeetings.jsp").forward(req, resp);
    }
}

/**
 */
public class SearchEmployeeServlet extends HttpServlet {
    private EmployeeService employeeService = new EmployeeService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String updateStatus = req.getParameter("updateStatus");
        if (updateStatus != null && "-1".equals(updateStatus)) {
            String empid = req.getParameter("empid");
            employeeService.updateEmpStatusById(Integer.parseInt(empid), Integer.parseInt(updateStatus));
        }
        String employeename = req.getParameter("employeename");
        String username = req.getParameter("username");
        String status = req.getParameter("status");
        String page = req.getParameter("page");
        String count = req.getParameter("count");
        if (status == null || "".equals(status)) {
            status = "1";
        }
        if (page == null || "".equals(page)) {
            page = "1";
        }
        if (count == null || "".equals(count)) {
            count = "10";
        }
        List<Employee> list = employeeService.searchEmp(employeename, username, Integer.parseInt(status), Integer.parseInt(page), Integer.parseInt(count));
        int totalCount = employeeService.getCount(employeename, username, Integer.parseInt(status));
        int totalPage = totalCount / Integer.parseInt(count) + 1;
        req.setAttribute("list", list);
        req.setAttribute("totalCount", totalCount);
        req.setAttribute("totalPage", totalPage);
        req.setAttribute("page", page);
        req.setAttribute("employeename", employeename);
        req.setAttribute("username", username);
        req.setAttribute("status", status);
        req.getRequestDispatcher("/searchemployees.jsp").forward(req, resp);
    }
}

/**
 */
public class LoginServlet extends HttpServlet {
    private EmployeeService employeeService = new EmployeeService();

    @Override
        if (count == null || "".equals(count)) {
            count = "10";
        }
        List<Employee> list = employeeService.searchEmp(employeename, username, Integer.parseInt(status), Integer.parseInt(page), Integer.parseInt(count));
        int totalCount = employeeService.getCount(employeename, username, Integer.parseInt(status));
        int totalPage = totalCount / Integer.parseInt(count) + 1;
        req.setAttribute("list", list);
        req.setAttribute("totalCount", totalCount);
        req.setAttribute("totalPage", totalPage);
        req.setAttribute("page", page);
        req.setAttribute("employeename", employeename);
        req.setAttribute("username", username);
        req.setAttribute("status", status);
        req.getRequestDispatcher("/searchemployees.jsp").forward(req, resp);
    }
}

/**
 */
public class LoginServlet extends HttpServlet {
    private EmployeeService employeeService = new EmployeeService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String accountname = req.getParameter("accountname");
        String password = req.getParameter("password");
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String depid = req.getParameter("depid");
        int i = departmentService.deleteDepById(Integer.parseInt(depid));
        if (i == 1) {
            resp.sendRedirect(req.getContextPath() + "/departments");
        } else {
            req.setAttribute("error", "删除失败");
            req.getRequestDispatcher("/departments").forward(req, resp);
        }
    }
}

/**
 */
public class MyBookingServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int loginEmpId = ((Employee) req.getSession().getAttribute("loginUser")).getEmployeeid();
        List<Meeting> mrs = meetingService.getMyBookingMeeting(loginEmpId);
        req.setAttribute("mrs", mrs);
        req.getRequestDispatcher("/mybookings.jsp").forward(req, resp);
    }
}


/**
 */
public class UpdateEmpStatusServlet extends HttpServlet {
    private EmployeeService employeeService = new EmployeeService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String status = req.getParameter("status");
        String empid = req.getParameter("empid");
        int i = employeeService.updateEmpStatusById(Integer.parseInt(empid), Integer.parseInt(status));
        if (i == 1) {
            resp.sendRedirect(req.getContextPath() + "/approveaccount");
        } else {
            req.setAttribute("error", "审批失败");
            req.getRequestDispatcher("/approveaccount").forward(req, resp);
        }
    }
}

/**
 */
public class UpdateDepServlet extends HttpServlet {
    private DepartmentService departmentService = new DepartmentService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }


/**
 */
public class MyBookingServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int loginEmpId = ((Employee) req.getSession().getAttribute("loginUser")).getEmployeeid();
        List<Meeting> mrs = meetingService.getMyBookingMeeting(loginEmpId);
        req.setAttribute("mrs", mrs);
        req.getRequestDispatcher("/mybookings.jsp").forward(req, resp);
    }
}

/**
 */
public class MyMeetingServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 */
public class MeetingDetailsServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String mid = req.getParameter("mid");
        String type = req.getParameter("type");
        Meeting meeting = meetingService.getMeetingDetailsByMeetingId(Integer.parseInt(mid));
        List<Employee> emps = meetingService.getEmps();
        req.setAttribute("mt", meeting);
        req.setAttribute("emps", emps);
        req.setAttribute("type", type);
        req.getRequestDispatcher("/meetingdetails.jsp").forward(req, resp);
    }
}

/**
 */
public class NotificationsServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
        } else if (login == 3) {
            req.setAttribute("error", "用户名或者密码输入错误,请重新登录");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        } else if (login == -1) {
            req.setAttribute("error", "账号已关闭,登陆失败,请联系管理员");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        }
    }
}

/**
 */
public class AddMeetingRoomServlet extends HttpServlet {
    private MeetingRoomService meetingRoomService = new MeetingRoomService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String roomid = req.getParameter("roomid");
        String roomnum = req.getParameter("roomnum");
        String roomname = req.getParameter("roomname");
        String capacity = req.getParameter("capacity");
        String status = req.getParameter("status");
        String description = req.getParameter("description");
        MeetingRoom meetingRoom = new MeetingRoom(Integer.parseInt(roomnum), roomname, Integer.parseInt(capacity), Integer.parseInt(status), description);
        if (roomid == null || "".equals(roomid)) {
            //添加会议室
            int result = meetingRoomService.insert(meetingRoom);
            if (result == 1) {
                //去查看会议室页面
                resp.sendRedirect(req.getContextPath() + "/getallmr");
            } else {
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String meetingname = req.getParameter("meetingname");
        String numberofparticipants = req.getParameter("numberofparticipants");
        String starttime = req.getParameter("starttime");
        String endtime = req.getParameter("endtime");
        String roomid = req.getParameter("roomid");
        String description = req.getParameter("description");
        String[] selSelectedEmployees = req.getParameterValues("selSelectedEmployees");
        //获取当前登录的用户对象
        Employee loginUser = (Employee) req.getSession().getAttribute("loginUser");
        Meeting meeting = new Meeting(meetingname, Integer.parseInt(roomid), loginUser.getEmployeeid(), Integer.parseInt(numberofparticipants), Timestamp.valueOf(starttime), Timestamp.valueOf(endtime), new Timestamp(System.currentTimeMillis()), description);
        meetingService.insert(meeting, selSelectedEmployees);
        resp.sendRedirect(req.getContextPath() + "/mybooking");
        //resp.sendRedirect(req.getContextPath() + "/mymeeting");
    }
}

/**
 */
public class DoRegServlet extends HttpServlet {
    private EmployeeService employeeService = new EmployeeService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String employeename = req.getParameter("employeename");
        String accountname = req.getParameter("accountname");
        String password = req.getParameter("password");
        String phone = req.getParameter("phone");
        String email = req.getParameter("email");
        String deptid = req.getParameter("deptid");
        String depName = req.getParameter("depName");
        int i = departmentService.updateDepById(depName, Integer.parseInt(id));
        PrintWriter out = resp.getWriter();
        if (i == 1) {
            out.write("修改成功");
        } else {
            out.write("修改失败");
        }
    }
}

/**
 */
public class AddDepServlet extends HttpServlet {
    private DepartmentService departmentService = new DepartmentService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String departmentname = req.getParameter("departmentname");
        int insert = departmentService.insert(departmentname);
        if (insert == 1) {
            resp.sendRedirect(req.getContextPath() + "/departments");
        } else {
            req.setAttribute("error", "添加失败");
            req.getRequestDispatcher("/departments").forward(req, resp);
        }
    }
}
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String accountname = req.getParameter("accountname");
        String password = req.getParameter("password");
        int login = employeeService.login(accountname, password);
        ServletContext sc = req.getServletContext();
        Object visitcount = sc.getAttribute("vc");
        if (visitcount == null) {
            visitcount = "0";
        }
        int vc = Integer.parseInt(visitcount.toString()) + 1;
        sc.setAttribute("vc", vc);
        if (login == 0) {
            req.setAttribute("error", "用户待审批,请稍候");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        } else if (login == 1) {
            req.getSession().setAttribute("loginUser", employeeService.getLoginUser());
            resp.sendRedirect(req.getContextPath() + "/notifications");
        } else if (login == 2) {
            req.setAttribute("error", "用户审批未通过,请重新注册");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        } else if (login == 3) {
            req.setAttribute("error", "用户名或者密码输入错误,请重新登录");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        } else if (login == -1) {
            req.setAttribute("error", "账号已关闭,登陆失败,请联系管理员");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        }
    }
}

/**
 */
public class AddMeetingRoomServlet extends HttpServlet {

/**
 */
public class UpdateDepServlet extends HttpServlet {
    private DepartmentService departmentService = new DepartmentService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        String id = req.getParameter("id");
        String depName = req.getParameter("depName");
        int i = departmentService.updateDepById(depName, Integer.parseInt(id));
        PrintWriter out = resp.getWriter();
        if (i == 1) {
            out.write("修改成功");
        } else {
            out.write("修改失败");
        }
    }
}

/**
 */
public class AddDepServlet extends HttpServlet {
    private DepartmentService departmentService = new DepartmentService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
        req.setAttribute("type", type);
        req.getRequestDispatcher("/meetingdetails.jsp").forward(req, resp);
    }
}

/**
 */
public class NotificationsServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int loginEmpId = ((Employee) req.getSession().getAttribute("loginUser")).getEmployeeid();
        List<Meeting> mt7 = meetingService.getMeeting7Days(loginEmpId);
        List<Meeting> cm = meetingService.getCanceledMeeting(loginEmpId);
        req.setAttribute("mt7", mt7);
        req.setAttribute("cm", cm);
        req.getRequestDispatcher("/notifications.jsp").forward(req, resp);
    }
}

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String employeename = req.getParameter("employeename");
        String accountname = req.getParameter("accountname");
        String password = req.getParameter("password");
        String phone = req.getParameter("phone");
        String email = req.getParameter("email");
        String deptid = req.getParameter("deptid");
        Employee employee = new Employee(employeename, accountname, phone, email, Integer.parseInt(deptid), password);
        int reg = employeeService.reg(employee);
        if (reg == 1) {
            //注册成功,跳转到登录页面
            resp.sendRedirect(req.getContextPath() + "/login.jsp");
        } else if (reg == -1) {
            //用户名重复,注册失败
            req.setAttribute("error", "用户名重复,注册失败");
            req.getRequestDispatcher("/reg").forward(req, resp);
        } else {
            req.setAttribute("error", "不明原因,注册失败");
            req.getRequestDispatcher("/reg").forward(req, resp);
        }
    }
}

/**
 */
public class PermissFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String servletPath = req.getServletPath();
        if ("/login.jsp".equals(servletPath) || "/reg".equals(servletPath) || "/doreg".equals(servletPath) || "/login".equals(servletPath) || servletPath.contains("/images/") || servletPath.contains("/js/") || servletPath.contains("/My97DatePicker/") || servletPath.contains("/styles/")) {
            chain.doFilter(req, response);
        } else {
            Object loginUser = req.getSession().getAttribute("loginUser");
            if (loginUser == null) {
                ((HttpServletResponse) response).sendRedirect(req.getContextPath() + "/login.jsp");
            } else {
                chain.doFilter(req, response);
            }
        }
    }


/**
 */
public class MyBookingServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int loginEmpId = ((Employee) req.getSession().getAttribute("loginUser")).getEmployeeid();
        List<Meeting> mrs = meetingService.getMyBookingMeeting(loginEmpId);
        req.setAttribute("mrs", mrs);
        req.getRequestDispatcher("/mybookings.jsp").forward(req, resp);
    }
}

/**
 */
public class MyMeetingServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);

/**
 */
public class SearchEmployeeServlet extends HttpServlet {
    private EmployeeService employeeService = new EmployeeService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String updateStatus = req.getParameter("updateStatus");
        if (updateStatus != null && "-1".equals(updateStatus)) {
            String empid = req.getParameter("empid");
            employeeService.updateEmpStatusById(Integer.parseInt(empid), Integer.parseInt(updateStatus));
        }
        String employeename = req.getParameter("employeename");
        String username = req.getParameter("username");
        String status = req.getParameter("status");
        String page = req.getParameter("page");
        String count = req.getParameter("count");
        if (status == null || "".equals(status)) {
            status = "1";
        }
        if (page == null || "".equals(page)) {
            page = "1";
        }
        if (count == null || "".equals(count)) {
            count = "10";
        }
        List<Employee> list = employeeService.searchEmp(employeename, username, Integer.parseInt(status), Integer.parseInt(page), Integer.parseInt(count));
        int totalCount = employeeService.getCount(employeename, username, Integer.parseInt(status));
        int totalPage = totalCount / Integer.parseInt(count) + 1;
        req.setAttribute("list", list);
        req.setAttribute("totalCount", totalCount);

/**
 */
public class SearchMeetingServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String meetingname = req.getParameter("meetingname");
        String roomname = req.getParameter("roomname");
        String reservername = req.getParameter("reservername");
        String reservefromdate = req.getParameter("reservefromdate");
        String reservetodate = req.getParameter("reservetodate");
        String meetingfromdate = req.getParameter("meetingfromdate");
        String meetingtodate = req.getParameter("meetingtodate");
        String page = req.getParameter("page");
        String count = req.getParameter("count");
        if (page == null || "".equals(page)) {
            page = "1";
        }
        if (count == null || "".equals(count)) {
            count = "10";
        }
        List<Meeting> list = meetingService.searchMeeting(meetingname, roomname, reservername, reservefromdate, reservetodate, meetingfromdate, meetingtodate, Integer.parseInt(page), Integer.parseInt(count));
        int totalCount = meetingService.getCount(meetingname, roomname, reservername, reservefromdate, reservetodate, meetingfromdate, meetingtodate);
        int totalPage = totalCount / Integer.parseInt(count) + 1;
        req.setAttribute("list", list);
        req.setAttribute("totalCount", totalCount);
        req.setAttribute("totalPage", totalPage);
        req.setAttribute("page", page);
        req.setAttribute("meetingname", meetingname);
        req.setAttribute("roomname", roomname);
        req.setAttribute("reservername", reservername);
        req.setAttribute("reservefromdate", reservefromdate);
        req.setAttribute("reservetodate", reservetodate);
        req.setAttribute("meetingfromdate", meetingfromdate);

/**
 */
public class DoBookMeetingServlet extends HttpServlet {
    private MeetingService meetingService = new MeetingService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String meetingname = req.getParameter("meetingname");
        String numberofparticipants = req.getParameter("numberofparticipants");
        String starttime = req.getParameter("starttime");
        String endtime = req.getParameter("endtime");
        String roomid = req.getParameter("roomid");
        String description = req.getParameter("description");
        String[] selSelectedEmployees = req.getParameterValues("selSelectedEmployees");
        //获取当前登录的用户对象
        Employee loginUser = (Employee) req.getSession().getAttribute("loginUser");
        Meeting meeting = new Meeting(meetingname, Integer.parseInt(roomid), loginUser.getEmployeeid(), Integer.parseInt(numberofparticipants), Timestamp.valueOf(starttime), Timestamp.valueOf(endtime), new Timestamp(System.currentTimeMillis()), description);
        meetingService.insert(meeting, selSelectedEmployees);
        resp.sendRedirect(req.getContextPath() + "/mybooking");
        //resp.sendRedirect(req.getContextPath() + "/mymeeting");
    }
}

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐