员工开会管理–基于SSM课设项目
成员:张慧、周钰雯、张雯雯、肖栋梁
一、项目搭建
1、新建maven项目
2、导依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
3、搭建项目结构
3.1、applicationContext.xml --spirng配置文件
<!-- spring配置扫描com.xzzz.meeting包,使用默认拦截器,controller不扫-->
<context:component-scan base-package="com.xzzz.meeting" use-default-filters="true">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
3.2、spring-servlet.xml --springmvc配置文件
<context:component-scan base-package="com.xzzz.meeting" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<mvc:annotation-driven/>
3.3、web.xml 全局配置文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注:需导入servlet-api依赖
4、测试部署tomcat
二、整合Mybatis
1、导入相关依赖
<dependency>
<groupId>org.springframew</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
2、添加db.properties文件
db.username=root
db.password=root
db.url=jdbc:mysql:///meeting?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
3、spring配置文件整Mybatis
<context:property-placeholder location="classpath:db.properties"/>
<!--导入数据源-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="username" value="${db.username}"></property>
<property name="password" value="${db.password}"></property>
<property name="url" value="${db.url}"></property>
</bean>
<!-- SqlSessionFactoryBean加载数据源-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="typeAliasesPackage" value="com.xzzz.meeting.model"></property>
<property name="mapperLocations">
<value>
classpath*:com/xzzz/meeting/mapper/*.xml
</value>
</property>
</bean>
<!-- mapperScannerConfigurer扫描mapper-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="mapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
<property name="basePackage" value="com.xzzz.meeting.mapper"/>
</bean>
注:配置文件如果放在java目录下要避免xml文件扫描被忽视的问题
解决:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
4、测试部门信息的查询
5、开启事务
<!-- 事务核心管理器,封装了所有事务操作. 依赖于连接池 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 以方法为单位,指定方法应用什么事务属性 isolation:隔离级别 propagation:传播行为 read-only:是否只读 -->
<tx:method name="add*"/>
<tx:method name="insert*"/>
<tx:method name="update*"/>
<tx:method name="delete*"/>
</tx:attributes>
</tx:advice>
<!-- 配置织入 -->
<aop:config>
<!-- 配置切点表达式 -->
<aop:pointcut expression="execution(* com.xzzz.meeting.service.*.*(..))" id="pc1" />
<!-- 配置切面 : 通知+切点 advice-ref:通知的名称 pointcut-ref:切点的名称 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc1" />
</aop:config>
三、整合Freemarker
1、导入Freemarker依赖
2、新建freemarker-var-properties文件
3、springmvc配置文件配置相关配置
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:freemarker-var.properties</value>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/ftl/"/>
<property name="defaultEncoding" value="UTF-8"/>
<property name="freemarkerVariables">
<map>
<entry key="root" value="${root}"/>
</map>
</property>
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">10</prop>
<prop key="locale">zh_CN</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<prop key="time_format">HH:mm:ss</prop>
<prop key="number_format">#.####</prop>
</props>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
<property name="suffix" value=".ftl"/>
<property name="allowRequestOverride" value="true"/>
<property name="allowSessionOverride" value="true"/>
<property name="exposeSessionAttributes" value="true"/>
<property name="exposeRequestAttributes" value="true"/>
<property name="contentType" value="text/html;charset=utf-8"/>
</bean>
4、ftl文件下建hello.ftl文件,conteroller实现测试
四、用户登录
1、页面展示
2、导入前端资源
注:springmvc中给静态资源放行
<mvc:resources mapping="/**" location="/"/>
3、导入用户数据
4、编写controller层调用service层dao层拿到数据
5、拿到数据导入首页登录界面显示出来
五、提取头部与左部菜单栏的抽取
1、头部提取到top.ftl
<div class="page-header">
<div class="header-banner">
<img src="images/header.png" alt="CoolMeeting"/>
</div>
<div class="header-title">
欢迎访问Cool-Meeting会议管理系统
</div>
<div class="header-quicklink">
欢迎您,
<#if currentuser??>
<strong>${currentuser.employeename!''}</strong>
</#if>
<a href="changepassword">[修改密码]</a>
</div>
</div>
2、<#include ‘top.ftl’>头文件的导入
3、左部菜单栏的抽取
<div class="page-sidebar">
<div class="sidebar-menugroup">
<div class="sidebar-grouptitle">个人中心</div>
<ul class="sidebar-menu">
<li class="sidebar-menuitem"><a href="notifications">最新通知</a></li>
<li class="sidebar-menuitem active"><a href="mybookings">我的预定</a></li>
<li class="sidebar-menuitem"><a href="mymeetings">我的会议</a></li>
</ul>
</div>
<div class="sidebar-menugroup">
<div class="sidebar-grouptitle">人员管理</div>
<ul class="sidebar-menu">
<li class="sidebar-menuitem"><a href="departments">部门管理</a></li>
<li class="sidebar-menuitem"><a href="register">员工注册</a></li>
<li class="sidebar-menuitem"><a href="approveaccount">注册审批</a></li>
<li class="sidebar-menuitem"><a href="searchemployees">搜索员工</a></li>
</ul>
</div>
<div class="sidebar-menugroup">
<div class="sidebar-grouptitle">会议预定</div>
<ul class="sidebar-menu">
<li class="sidebar-menuitem"><a href="addmeetingroom">添加会议室</a></li>
<li class="sidebar-menuitem"><a href="meetingrooms">查看会议室</a></li>
<li class="sidebar-menuitem"><a href="bookmeeting">预定会议</a></li>
<li class="sidebar-menuitem"><a href="searchmeetings">搜索会议</a></li>
</ul>
</div>
</div>
六、用户注册准备
1、后端接口调用数据库拿到部门信息
@RequestMapping("/register")
public String register(Model model) {
List<Department> deps = departmentService.getAllDeps();
model.addAttribute("deps", deps);
return "register";
}
2、前端显示到页面
<script>
function check() {
var password = document.getElementById('password');
var confirm = document.getElementById('confirm');
var confirminfo = document.getElementById('confirminfo');
if (password.value != confirm.value) {
confirminfo.innerHTML = '两次输入密码不一致';
}else{
confirminfo.innerHTML = '';
}
}
</script>
<select name="departmentid">
<#if deps??>
<#list deps as dep>
<option value="${dep.departmentid}">${dep.departmentname}</option>
</#list>
</#if>
</select>
七、用户注册
1、后端接口的实现
@RequestMapping("/doReg")
public String doReg(Employee employee,Model model) {
Integer result = employeeService.doReg(employee);
if (result == 1) {
return "redirect:/";
}else{
model.addAttribute("error", "注册失败,账户名已存在");
model.addAttribute("employee", employee);
return "forward:/register";
}
}
2、前端数据回显
<input name="employeename" type="text" value="<#if employee??>${employee.employeename}</#if>" id="employeename" maxlength="20"/>
3、页面效果
八、权限管理
1、添加拦截器的类
public class PermissInterceptor implements HandlerInterceptor {
AntPathMatcher pathMatcher = new AntPathMatcher();
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
if ("/".equals(requestURI) || "/doLogin".equals(requestURI) || "/register".equals(requestURI) || "/doReg".equals(requestURI)) {
return true;
}
HttpSession session = request.getSession(true);
Employee currentuser = (Employee) session.getAttribute("currentuser");
if (pathMatcher.match("/admin/**", requestURI)) {
if (currentuser != null) {
if (currentuser.getRole() == 2) {
return true;
}else{
response.getWriter().write("forbidden");
return false;
}
}
} else {
if (currentuser != null) {
return true;
}
}
response.sendRedirect("/");
return false;
}
}
2、spirngmvc中配置拦截该类
<!-- 除静态资源外,拦截PermissInterceptor类下的方法-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/images/**"/>
<mvc:exclude-mapping path="/styles/**"/>
<bean class="com.xzzz.meeting.interceptor.PermissInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
注:当用户为员工身份时,输入admin/department会判断role身份,员工仍会被拦截返回禁止
3、权限授予
<#if currentuser?? && (currentuser.role==2)>
<li class="sidebar-menuitem"><a href="/admin/departments">部门管理</a></li>
<li class="sidebar-menuitem"><a href="/admin/approveaccount">注册审批</a></li>
<li class="sidebar-menuitem"><a href="/admin/searchemployees">搜索员工</a></li>
</#if>
九、用户审批
1、添加审批接口,查询所有待审批的用户放入emps。
@Controller
@RequestMapping("/admin")
public class ApproveaccountController {
public static final Integer PENDING_APPROVE = 0;
@Autowired
EmployeeService employeeService;
@RequestMapping("/approveaccount")
public String approveaccount(Model model) {
model.addAttribute("emps", employeeService.getAllEmpsByStatus(PENDING_APPROVE));
return "approveaccount";
}
}
2、前端页面遍历emps里的数据回显到审批页面
<#if emps ??>
<#list emps as emp>
<tr>
<td>${emp.employeename}</td>
<td>${emp.username}</td>
<td>${emp.phone}</td>
<td>${emp.email}</td>
<td>
<a type="button" class="clickbutton" href="/admin/updatestatus?employeeid=${emp.employeeid}&status=1">通过</a>
<a type="button" class="clickbutton" href="/admin/updatestatus?employeeid=${emp.employeeid}&status=2">不通过</a>
</td>
</tr>
</#list>
</#if>
十、部门管理
1、页面展示
2、页面部门的信息显示
具体实现:
后端:查询到数据库的部门信息存放到deps
@RequestMapping("/departments")
public String departments(Model model) {
model.addAttribute("deps", departmentService.getAllDeps());
return "departments";
}
前端:拿到deps里的数据回显到页面展示
<#if deps??>
<#list deps as dep>
<tr>
<td>${dep.departmentid}</td>
<td id="depname${dep.departmentid}">${dep.departmentname}</td>
<td>
<a class="clickbutton" href="#" id="edit${dep.departmentid}"
onclick="editDep(${dep.departmentid})">编辑</a>
<a class="clickbutton" style="display: none" href="#" id="cancel${dep.departmentid}"
onclick="cancelDep(${dep.departmentid})">取消</a>
<a class="clickbutton" href="/admin/deletedep?departmentid=${dep.departmentid}">删除</a>
</td>
</tr>
</#list>
</#if>
3、添加部门功能
具体实现:
后端:根据输入的部门名称到数据库查询出部门信息,如果数据库部门名存在,返回-1,反之完成添加功能。
@RequestMapping("/adddepartment")
public String adddepartment(String departmentname) {
departmentService.adddepartment(departmentname);
return "redirect:/admin/departments";
}
前端:点击添加按钮提交表单完成添加功能的实现。
<form action="/admin/adddepartment">
<fieldset>
<legend>添加部门</legend>
部门名称:
<input type="text" id="departmentname" name="departmentname" maxlength="20"/>
<input type="submit" class="clickbutton" value="添加"/>
</fieldset>
</form>
4、删除功能的实现
具体实现:
后端:根据部门的id实现删除部门信息。
@RequestMapping("/deletedep")
public String deletedep(Integer departmentid) {
departmentService.deletedep(departmentid);
return "redirect:/admin/departments";
}
前端:调用/admin/deletedepdepartmentid=${dep.departmentid}接口
<a class="clickbutton" href="/admin/deletedep?departmentid=${dep.departmentid}">删除</a>
5、编辑功能的实现
具体实现
后端:
添加一个更新接口,实现根据部门id到数据库更新部门名称
@RequestMapping("/updatedep")
@ResponseBody
public String updatedep(Integer id, String name) {
Integer result = departmentService.updatedep(id, name);
if (result == 1) {
return "success";
}
return "error";
}
前端:先拿到编辑、取消、部门名的标签, 当点击编辑判断取消按钮是否显示,没显示则显示, 编辑按钮文本变成”确定“,然后拿到部门名文本换成文本框。 得到文本框的内容,输出一个post请求调用后端接口完成查询工作。
function editDep(depid) {
// 先拿到编辑、取消、部门名的标签
var editBtn = $('#edit' + depid);
var cancelBtn = $('#cancel' + depid);
var ele = $('#depname' + depid);
depname = ele.html();
// 当点击编辑判断取消按钮是否显示,没显示则显示, 编辑按钮文本变成”确定“,然后拿到部门名文本换成文本框。
if (cancelBtn.css('display') == 'none') {
cancelBtn.css('display', 'inline');
editBtn.html('确定');
var depName = ele.text();
ele.html('<input type="text" value="' + depName + '" />')
}else{
// 得到文本框的内容,输出一个post请求调用后端接口完成查询工作
var children = ele.children('input');
var val = children.val();
$.post('/admin/updatedep',{id:depid,name:val},function (msg) {
if (msg == 'success') {
cancelBtn.css('display', 'none');
editBtn.html('编辑');
ele.html(val);
}
})
}
十一、搜索员工
页面展示
1、员工信息的展示
后端:查询到status=1的带分页的所有员工信息
<a href="/admin/searchemployees?status=1">搜索员工</a>
@RequestMapping("/searchemployees")
public String getAllEmployees(Employee employee, @RequestParam(defaultValue = "1") Integer page, Model model) {
List<Employee> emps = employeeService.getAllEmps(employee, page, PAGE_SIZE);
Long total = employeeService.getTotal(employee);
System.out.println(emps);
model.addAttribute("emps", emps);
model.addAttribute("total", total);
model.addAttribute("page", page);
model.addAttribute("pagenum", total % PAGE_SIZE == 0 ? total / PAGE_SIZE : total / PAGE_SIZE + 1);
return "searchemployees";
}
查询sql语句
<select id="getAllEmps" resultType="com.xzzz.meeting.model.Employee">
select * from employee where status=#{emp.status}
<if test="emp.employeename!=null">
and employeename like concat('%',#{emp.employeename},'%')
</if>
<if test="emp.username!=null">
and username like concat('%',#{emp.username},'%')
</if>
limit #{page},#{pagesize}
</select>
<select id="getTotal" resultType="java.lang.Long">
select count(*) from employee where status=#{status}
<if test="employeename!=null">
and employeename like concat('%',#{employeename},'%')
</if>
<if test="username!=null">
and username like concat('%',#{username},'%')
</if>
</select>
前端:
<#if emps??>
<#list emps as emp>
<tr>
<td>${emp.employeename}</td>
<td>${emp.username}</td>
<td>${emp.phone}</td>
<td>${emp.email}</td>
<td>
<a class="clickbutton" href="/admin/updateemp?id=${emp.employeeid}">关闭账号</a>
</td>
</tr>
</#list>
</#if>
2、分页功能的完善
页面效果:
后端:
查询到的数据放入model
model.addAttribute("emps", emps);
model.addAttribute("total", total);
model.addAttribute("page", page);
model.addAttribute("pagenum", total % PAGE_SIZE == 0 ? total / PAGE_SIZE : total / PAGE_SIZE + 1);
前端:页数的数据展示
<div class="header-info">
共<span class="info-number">${total}</span>条结果,
分成<span class="info-number">${pagenum}</span>页显示,
当前第<span class="info-number">${page}</span>页
</div>
还有页面的跳转以及首页、末页的效果
<form action="/admin/searchemployees" style="display: inline" method="get">
跳到第<input name="page" type="text" id="pagenum" class="nav-number"/>页
<input name="employeename" type="text" id="employeename"
value="<#if employee??>${employee.employeename!''}</#if>" style="display: none"/>
<input name="username" type="text" id="accountname"
value="<#if employee??>${employee.username!''}</#if>" style="display: none"/>
<input name="status" type="text" id="status"
value="1" style="display: none"/>
<input type="submit" class="clickbutton" value="跳转"/>
</form>
搜索员工功能实现
前端:
<form action="/admin/searchemployees" method="get">
<fieldset>
<legend>搜索员工</legend>
<table class="formtable">
<tr>
<td>姓名:</td>
<td>
<input name="employeename" type="text" id="employeename"
value="<#if employee??>${employee.employeename!''}</#if>" maxlength="20"/>
</td>
<td>账号名:</td>
<td>
<input name="username" type="text" id="accountname"
value="<#if employee??>${employee.username!''}</#if>" maxlength="20"/>
</td>
<td>状态:</td>
<td>
<#if employee??>
<#if employee.status==0>
<input type="radio" id="status" name="status" value="1"/><label>已批准</label>
<input checked="checked" type="radio" id="status" name="status" value="0"/><label>待审批</label>
<input type="radio" id="status" name="status" value="2"/><label>已关闭</label>
<#elseif employee.status==1>
<input checked="checked" type="radio" id="status" name="status" value="1"/><label>已批准</label>
<input type="radio" id="status" name="status" value="0"/><label>待审批</label>
<input type="radio" id="status" name="status" value="2"/><label>已关闭</label>
<#elseif employee.status==2>
<input type="radio" id="status" name="status" value="1"/><label>已批准</label>
<input type="radio" id="status" name="status" value="0"/><label>待审批</label>
<input checked="checked" type="radio" id="status" name="status" value="2"/><label>已关闭</label>
</#if>
<#else>
<input type="radio" id="status" name="status" value="1"
checked="checked"/><label>已批准</label>
<input type="radio" id="status" name="status" value="0"/><label>待审批</label>
<input type="radio" id="status" name="status" value="2"/><label>已关闭</label>
</#if>
</td>
</tr>
<tr>
<td colspan="6" class="command">
<input type="submit" class="clickbutton" value="查询"/>
<input type="reset" class="clickbutton" value="重置"/>
</td>
</tr>