背景
本人大二java实训期间第一次做的一个比较完整(有登录、注册以及后台管理界面)的小型学生信息管理系统,大概花了2周左右的时间,功能也就是最基础的增删改查,用的是最基础的java-swing组件。大三开了一门jsp程序设计的课程,由于老师讲的比较枯燥,按照ppt一个个的知识点讲述实在是无聊,于是我自己花了50块钱在网上买了一个jsp+servlet+mysql的项目。我从头到尾跟着视频敲了一遍加上要理解以及解决期间遇到的bug大概花了3、4周的时间。后面自己用jsp设计了一个简单的系统参加学校比赛获得了三等奖。不过眼看快要毕业了如果只会jsp肯定是很难找到到工作的,于是在学习网站上又找了一个ssm框架的项开始自学,又花了一个月的时间,然后自己做了一个期刊在线投稿系统,由于还是初学,所以花了大概一个半月的时间从需求到设计再到实现。
一、 相关技术简介
技术路线
1.前端
easyui(界面设计)+ajax(发送请求数据)
2.后端
spring(容器) + springmvc(处理请求) + mybatis(数据库框架)
相关环境
1.编译、运行工具
jdk1.8
2.数据库
mysql8.0
3.服务器
tomcat8.5
相关工具
1.代码编辑工具
eclipse
2.数据库可视化管理工具
navicat
二、系统功能介绍
系统有三个角色,作者、专家、编辑,业务流程:作者投稿 -> 专家审核 -> 编辑复审 - >稿件发布。
作者模块
1.稿件信息管理
(1)作者如果没有注册过先进行注册、注册成功后跳转到登录界面
(2)作者登录后进入系统,可在线投递稿件、投递成功后稿件变为待审核状态
(3)可以查询各种状态的稿件信息、以及作者投递的所有稿件列表
2.个人信息管理
作者可以对个人信息进行查看、修改操作
专家模块
1.稿件信息管理
(1)专家登录后(账号、密码由管理员提供)进入管理系统,可以下载编辑分配的稿件进行审核,审核通过后稿件状态变为已通过,审核未通过状态变为未通过。
(2)专家可以查看编辑分配的稿件列表
2.个人信息管理
专家可以对个人信息进行查看、修改操作
编辑模块
1.稿件信息管理
(1)编辑可以在线分配稿件给专家进行审核
(2)编辑可以复审专家已审核通过的稿件
(3)编辑可以查看所有用户投递过来的稿件
2.稿件类别管理
编辑可以添加、修改、删除稿件类别(如果此稿件类别含有稿件则不允许删除操作)
3.用户信息管理
编辑可以查看作者、专家基本信息
4.个人信息管理
编辑可以对个人信息进行查看、修改操作
三、系统实现
由于三个模块代码实现差不多以下显示作者模块
作者实体
@Component
public class User {
private int id;
private String username;
private String password;
private String author_name;
private String sex;
private String phone_number;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAuthor_name() {
return author_name;
}
public void setAuthor_name(String author_name) {
this.author_name = author_name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getPhone_number() {
return phone_number;
}
public void setPhone_number(String phone_number) {
this.phone_number = phone_number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
作者控制器
@RequestMapping("/author")
@Controller
public class AuthorController {
@Autowired
private AuthorService authorService;
@Autowired
private UserDao userDao;
@Autowired
private UserService userService;
@Autowired
private EditorService editorService;
@RequestMapping(value="/index",method=RequestMethod.GET)
public ModelAndView index(ModelAndView model,HttpServletRequest request) {
int id = (Integer) request.getSession().getAttribute("id");
User user = authorService.queryOwnInfo(id);
model.addObject("user",user);
model.setViewName("author/index");
return model;
}
/**
* 跳转到添加稿件页面
*/
@RequestMapping(value="/add",method=RequestMethod.GET)
public ModelAndView add(ModelAndView model) {
Map<String,Object> queryMap = new HashMap();
List<Nav> list = editorService.findNavList(queryMap);
model.addObject("dataList",list);
model.setViewName("author/addManuscript");
return model;
}
/**
* 处理用户上传稿件请求
* @return
*/
@RequestMapping(value="/upload_file",method=RequestMethod.POST)
@ResponseBody
public Map<String,String> upload(Manuscript manuscript,MultipartFile manuscript_file,HttpServletRequest request,
HttpServletResponse response
) throws IOException{
Map<String,String> ret = new HashMap<String,String>();
if(StringUtils.isEmpty(manuscript.getAuthor_name())) {
ret.put("type","error");
ret.put("msg","作者姓名不能为空!");
return ret;
}
String author_name = request.getSession().getAttribute("author_name").toString();
if(!manuscript.getAuthor_name().equals(author_name)) {
ret.put("type","error");
ret.put("msg","请输入正确的姓名!");
return ret;
}
if(StringUtils.isEmpty(manuscript.getTitle())) {
ret.put("type","error");
ret.put("msg","稿件标题不能为空!");
return ret;
}
if(StringUtils.isEmpty(manuscript.getSummary())) {
ret.put("type","error");
ret.put("msg","稿件摘要不能为空!");
return ret;
}
if(manuscript_file==null) {
ret.put("type","error");
ret.put("msg","文件没有选择");
return ret;
}
if(manuscript_file.getSize() > 10485760){
//文件没有选择
ret.put("type", "error");
ret.put("msg", "文件大小超过10M!");
return ret;
}
String suffix = manuscript_file.getOriginalFilename().substring(manuscript_file.getOriginalFilename().lastIndexOf(".")+1,manuscript_file.getOriginalFilename().length());
if(!"docx,doc,pdf".contains(suffix)) {
ret.put("type","error");
ret.put("msg","文件格式不正确!");
return ret;
}
String savePath = request.getServletContext().getRealPath("/")+"\\upload\\";
File savePathFile = new File(savePath);
if(!savePathFile.exists()) {
savePathFile.mkdir();
}
String fileName = new Date().getTime()+"."+suffix;
ret.put("src",request.getServletContext().getContextPath() + "/upload/" + fileName);
manuscript_file.transferTo(new File(savePath+fileName));
manuscript.setFilePath(ret.get("src"));
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String format = sf.format(new Date());
manuscript.setSubmit_time(format);
manuscript.setId((Integer)request.getSession().getAttribute("id"));
manuscript.setState("待审核");
if(authorService.add(manuscript)<=0) {
ret.put("type","error");
ret.put("msg","稿件添加失败!");
return ret;
}
ret.put("type", "success");
ret.put("msg", "文件上传成功!");
return ret;
}
/**
* 跳转到查询稿件的页面
*/
@RequestMapping(value="/queryManuscript",method=RequestMethod.GET)
public ModelAndView queryManuscript(ModelAndView model) {
model.setViewName("author/queryManuscript");
return model;
}
/**
* 显示稿件数据列表
* @param manuscript
* @param manuscript_file
* @param request
* @param
* @return
* @throws IOException
*/
@RequestMapping(value="/get_list",method=RequestMethod.POST)
@ResponseBody
public Map<String,Object> getList(
@RequestParam(value="state",required=true,defaultValue="") String state,
Page page,
HttpServletRequest request,HttpServletResponse response
){
Map<String,Object> ret = new HashMap<String,Object>();
Map<String,Object> queryMap = new HashMap<String,Object>();
System.out.print(state);
page.setOffset();
queryMap.put("offset",page.getOffset());
queryMap.put("pageSize",page.getRows());
queryMap.put("state","%"+state+"%");
int id = (Integer) request.getSession().getAttribute("id");
queryMap.put("id",id);
List<Manuscript> list = authorService.findListById(queryMap);
ret.put("rows",list);
ret.put("total",authorService.getTotal(queryMap));
return ret;
}
/**
* 跳转到查询个人信息的页面
*/
@RequestMapping(value="/queryOwnInfo",method=RequestMethod.GET)
public ModelAndView queryOwnInfo(ModelAndView model) {
model.setViewName("author/queryOwnInfo");
return model;
}
/**
* 处理用户查询个人信息请求
* @param author_name
* @param title
* @param page
* @return
*/
@RequestMapping(value="/getOwnInfo",method=RequestMethod.POST)
@ResponseBody
public Map<String,Object> getOwnInfo(
HttpServletRequest request,HttpServletResponse response
){
Map<String,Object> ret = new HashMap<String,Object>();
int id = (Integer) request.getSession().getAttribute("id");
User user = authorService.queryOwnInfo(id);
List<User> list = new ArrayList();
list.add(user);
ret.put("rows",list);
ret.put("total",1);
return ret;
}
/**
* 跳转到修改个人信息的页面
*/
@RequestMapping(value="/editOwnInfo",method=RequestMethod.GET)
public ModelAndView editOwnInfo(ModelAndView model) {
model.setViewName("author/editOwnInfo");
return model;
}
@RequestMapping(value="/editOwnInfo",method=RequestMethod.POST)
@ResponseBody
public Map<String,String> register(User user){
Map<String,String> ret = new HashMap<String,String>();
if(StringUtils.isEmpty(user.getUsername())) {
ret.put("type","error");
ret.put("msg","用户名不能为空!");
return ret;
}
if(StringUtils.isEmpty(user.getPassword())) {
ret.put("type","error");
ret.put("msg","密码不能为空!");
return ret;
}
if(StringUtils.isEmpty(user.getAuthor_name())) {
ret.put("type","error");
ret.put("msg","姓名不能为空!");
return ret;
}
if(StringUtils.isEmpty(user.getPhone_number())) {
ret.put("type","error");
ret.put("msg","电话号码不能为空!");
return ret;
}
if(user.getPhone_number().length()!=11) {
ret.put("type","error");
ret.put("msg","电话号码应为11位!");
return ret;
}
/**
* 验证手机号码的正确性
*/
String regex = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(user.getPhone_number());
boolean isMatch = m.matches();
if (!isMatch) {
ret.put("type","error");
ret.put("msg","请输入正确的手机号");
return ret;
}
if(StringUtils.isEmpty(user.getAddress())) {
ret.put("type","error");
ret.put("msg","居住地址不能为空!");
return ret;
}
if(authorService.editOwnInfo(user) <= 0) {
ret.put("type","error");
ret.put("msg","修改失败!");
return ret;
}
ret.put("type","success");
ret.put("msg","修改成功!");
return ret;
}
}
这里返回给前端的数据类型是Json,需要在方法上加上@ResponseBody注解,方法返回类型使用map类型,当然也可以自定义一个返回类,在实际项目开发中控制器是不允许有这么多代码的,控制器方法一般只有一、二行代码调用service层将入参传给service即可,因为处理业务就是service做的事情,现在由于都使用前后端分离模式开发,后端只需要提供接口供前端调用即可,有几个接口,控制器就有几个方法。
作者-service
@Service
public interface AuthorService {
public int add(Manuscript manuscript);
public int getTotal(Map<String,Object> queryMap);
public User queryOwnInfo(int id);
public int editOwnInfo(User user);
public List<Manuscript> findListById(Map<String,Object> queryMap);
}
作者实现类impl
@Service
public class AuthorServiceImpl implements AuthorService{
@Autowired
private AuthorDao authorDao;
public int add(Manuscript manuscript) {
// TODO Auto-generated method stub
return authorDao.add(manuscript);
}
public int getTotal(Map<String, Object> queryMap) {
// TODO Auto-generated method stub
return authorDao.getTotal(queryMap);
}
public User queryOwnInfo(int id) {
// TODO Auto-generated method stub
return authorDao.queryOwnInfo(id);
}
public int editOwnInfo(User user) {
// TODO Auto-generated method stub
return authorDao.editOwnInfo(user);
}
public List<Manuscript> findListById(Map<String, Object> queryMap) {
// TODO Auto-generated method stub
return authorDao.findListById(queryMap);
}
}
作者dao
@Repository
public interface AuthorDao {
public int add(Manuscript munscript);
public int getTotal(Map<String,Object> queryMap);
public User queryOwnInfo(int id);
public int editOwnInfo(User user);
public List<Manuscript> findListById(Map<String,Object> queryMap);
}
作者mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.onlineSubmit.dao.AuthorDao">
<update id="add" parameterType="Manuscript">
insert into manuscript(manuscript_id,id,author_name,title,summary,submit_time,filePath,state,nav_id) values(null,#{id},#{author_name},#{title},#{summary},#{submit_time},#{filePath},#{state},#{nav_id})
</update>
<update id="editOwnInfo" parameterType="User">
update user set username = #{username},password = #{password},author_name = #{author_name},sex = #{sex},phone_number = #{phone_number},address=#{address} where id = #{id}
</update>
<select id="findList" parameterType="Map" resultType="Manuscript">
select * from manuscript where author_name like #{author_name} and title like #{title} limit #{offset},#{pageSize}
</select>
<select id="getTotal" parameterType="Map" resultType="Integer">
select count(*) from manuscript where id=#{id} and state like #{state}
</select>
<select id="queryOwnInfo" parameterType="Integer" resultType="User">
select * from user where id = #{id}
</select>
<select id="findListById" parameterType="Map" resultType="Manuscript">
select * from manuscript where id = #{id} and state like #{state} limit #{offset},#{pageSize}
</select>
</mapper>
四、系统运行界面
登录界面
注册界面
稿件上传
稿件列表
稿件分配
在线审核
补充说明
不足之处
本系统需求阶段没有做充分,导致系统实现后与实际还是存在较大差异,仍然存在很多缺陷,比如:
1.系统只设定了一个专家,但实际应该有多个
2.专家审核时,没有设计文本框让专家输入意见(之后会加上这块需求)
3.重复代码过多,没有进行优化
4.控制层做了业务层的事情,系统耦合度提高,不好维护
2021-03-29 对系统部分功能的修改以及补充说明
1.系统现在可以设定多位专家,编辑可以将稿件分配给指定专家
2.增设管理员模块,可以对用户信息(系统所有用户)进行增删改查操作,也可以切换用户权限
3.专家、编辑审核稿件时,可以输入自己的意见,编辑可以查看专家的审稿记录
4.作者可以对稿件信息进行修改,然后重新上传
5.表结构变动,删除专家、编辑实体表,用户表增加user_type字段,以区分用户类别。
对应功能运行截图
管理员模块
切换用户权限
稿件分配给指定专家
专家审稿记录列表
稿件审核
关于2020-05-02对系统功能的改动
1.添加了主编模块,审稿流程调整为:
作者上传稿件 -> 专家审核 -> 编辑复审 -> 主编终审 ->稿件发布
2. 主编模块包含查询所有状态的稿件;对编辑审核通过的稿件进行终审。主编对自己信息的查看与修改操作。
主编查询稿件:
终审操作与专家、编辑类似。
主编唯一性逻辑:
2022-06-20 对系统做的一些更新(这可能是最后一版,后面不打算更新了)
总的来说,做了以下几点更新:
1.界面样式做了一些优化,比之前好看一点,包括背景图片、图标样式、文字样式…
2.添加了稿件发布模块,游客可以不用登录即可访问系统已发布稿件,也可以给喜欢的稿件进行点赞
系统部分运行截图:
登录界面:
稿件发布界面:
文章详情页面:
作者模块:
个人信息:
专家审稿记录:
修改审稿意见:
编辑模块:
限于篇幅运行截图,就不再贴截图了。
其他
1.需要用来做毕设或者课设参考的可以联系我(QQ:1172820051)
2.数据库脚本文件附在文件夹中,如运行失败,可以尝试使用命令行,从下往上运行即可
3.可以在微信公众号搜索“程序员阿坤”或者扫描下方二维码,加入我的公众号,目前“项目学习小组”正在热更基于springboot+vue的前后端分离的期刊在线投稿系统(技术和功能都做了调整有很多亮点!)公众号会有详细介绍,另外公众号会定时分享学习方法,以及一些工作中的技术干货一起学习交流!