在Spring MVC框架下,基于注解映射和数据绑定编写Java业务代码,采用MongoDB数据库进行数据存储,使用JSP和JS渲染表单页面,利用RESTful API实现基于URL的请求处理服务,以实现简单的用户留言与邮件反馈功能。通过IDEA IDE工具搭建好Spring MVC框架并连接MongoDB数据库后,即可进行该功能的实现。Spring MVC框架环境搭建可参考Spring MVC框架的环境部署与配置,MongoDB数据库安装及基本操作参考MongoDB学习笔记。

Spring MVC运行流程

  1. 客户端请求提交到DispatcherServlet;
  2. 由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller;
  3. DispatcherServlet将请求提交到Controller;
  4. Controller调用业务逻辑处理后,返回ModelAndView;
  5. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图;
  6. 视图负责将结果显示到客户端。

Domain与Dto对象

Domain对象

/*** UserFeedback.java* * @author Zero*///@Document>>将domain依赖注入MongoDB Repository
@Document(collection = "UserFeedback")
//UserFeedback类通过AbstractDomain实现了java.io.Serializable接口,其实例可安全的将数据保存到HttpSession中
public class UserFeedback extends AbstractDomain {private static final long serialVersionUID = 3843558621545635010L;//姓名private String fullName;//职位private String position;//电话private String phone;//留言类型private FeedbackType contentType;//留言内容private String content;//留言状态private FeedbackStatus status;public UserFeedback() {}public String fullName() {return fullName;}public UserFeedback fullName(String fullName) {this.fullName = fullName;return this;}//此处省略其他属性的get/set方法@Overridepublic String toString() {return "UserFeedback{" +"fullName='" + fullName + '\'' +", position='" + position + '\'' +", phone='" + phone + '\'' +", contentType='" + contentType + '\'' +", content='" + content + '\'' +", status=" + status +'}';}
}

DTO对象

/*** UserFeedbackFormDto.java* * @author Zero*/
public class UserFeedbackFormDto extends AbstractDto {private static final long serialVersionUID = -5003694127258885488L;//姓名private String fullName;//职位private String position;//电话private String phone;//留言类型private FeedbackType contentType;//留言内容private String content;private String captcha;public UserFeedbackFormDto() {}public UserFeedbackFormDto(UserFeedback userfeedback) {super(userfeedback);this.fullName = userfeedback.fullName();this.position = userfeedback.position();this.phone = userfeedback.phone();this.contentType = userfeedback.contentType();this.content = userfeedback.content();}public UserFeedbackFormDto(FeedbackType feedbackType) {this.contentType = feedbackType;}public FeedbackType[] getFeedbackTypes(){return FeedbackType.values();}//此处省略其他属性set/get方法public static List<UserFeedbackFormDto> toDtos(List<UserFeedback> list) {List<UserFeedbackFormDto> dtos = new ArrayList<>(list.size());dtos.addAll(list.stream().map(UserFeedbackFormDto::new).collect(Collectors.toList()));return dtos;}
}

基于注解的控制器

Controller类

使用一个基于注解的控制器可以处理多个动作,利用Dispatcher Servlet实现请求转发,利用RESTful API实现基于URL的请求处理服务,通过调用封装了后端复杂逻辑的Servlet类实现业务逻辑处理。而且使用@RequestingMapping注解类型即可对一个方法进行请求处理,其请求映射不需要存储在配置文件中。控制器部分的代码如下:

/*** UserFeedbackEmailController.java* 留言&&反馈** @author Zero*///@Controller>>标识类是一个hander处理器
@Controller
//@RequestingMapping>>注解控制器类时则所有的方法都将映射为类级别的请求,value属性将URL映射到方法
@RequestMapping("/contact/")
public class UserFeedbackEmailController {//@Autowired>>service实例注入controller,@Autowiredprivate UserFeedbackService userFeedbackService;//@RequestingMapping>>标识方法时则为一个请求处理方法,method属性指示该方法仅处理的http类型,返回值解析为跳转路径@RequestMapping(value = "feedback_form", method = RequestMethod.POST)//@ModelAttribute>>前端请求参数绑定到formDto入参,formDto对象添加到model,返回类型为string时则为逻辑视图名public String sendFeedbackEmail(@ModelAttribute("formDto") @Valid UserFeedbackFormDto formDto, BindingResult result, Model model, HttpServletRequest request) {//检查captchafinal String correctCaptcha = WebUtils.getCaptchaKey(request.getSession());final String captcha = formDto.getCaptcha();if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(correctCaptcha)) {result.rejectValue("captcha", null, "验证码错误");return "front/contact";}@Valid>>validator验证器,判断bindingResult.hasErrors(),有误则返回dto对应Validator定制消息提示if (result.hasErrors()) {return "front/contact";}//service实现类调用sendFeedbackEmail方法,以实现具体的业务处理String contactResult = userFeedbackService.sendFeedbackEmail(formDto);//创建model实例,传数据到前端model.addAttribute("contactResult", contactResult);//redirect经过client,避免user重新加载页面时再调用相同actionreturn "redirect:../contact";}
}

Validator类

控制器中使用了JSR 303 验证器,通过注解给对象属性添加约束以及定制错误消息。提交表单中的数据传输对象UserFeedbackFormDto对应的验证器代码如下:

/*** UserFeedbackFormDtoValidator.java* 验证表单对象* * @author Zero*///@Component>>把普通pojo实例化到spring容器,这里把validator注入spring容器中
@Component
//validator接口:validator编程实现数据验证的接口
public class UserFeedbackFormDtoValidator implements Validator {@Override//supports方法:判断当前验证器是否支持指定的clazz验证,如果支持返回truepublic boolean supports(Class<?> clazz) {return UserFeedbackFormDto.class.equals(clazz);}@Override//validate方法:验证目标对象target,将验证错误填入包含一系列FieldError和ObjectError对象的Errors对象//Errors对象中的错误信息,可利用表单标签库的Errors标签显示在HTML页面,错误消息可通过Spring支持的国际化特性进行本地化public void validate(Object target, Errors errors) {//给Errors对象添加错误的方法:在Errors对象上调用一个reject或rejectValue方法//ValidationUtils是一个有助于编写Validator的工具类ValidationUtils.rejectIfEmptyOrWhitespace(errors, "fullName", null, "姓名不能为空!");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "position", null, "职位不能为空!");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "contentType", null, "留言类型为选择!");ValidationUtils.rejectIfEmptyOrWhitespace(errors, "content", null, "留言内容不能为空!");UserFeedbackFormDto formDto = (UserFeedbackFormDto) target;validatePhoneNumber(formDto, errors);}private void validatePhoneNumber(UserFeedbackFormDto formDto, Errors errors) {final String phoneNumber = formDto.getPhone();if (StringUtils.isEmpty(phoneNumber)) {errors.rejectValue("phone", null, "电话号码不能为空!");return;}if (!MatchUtils.isPhoneNumber(phoneNumber)) {errors.rejectValue("phone", null, "电话号码格式错误!");}}
}

业务逻辑实现

Service接口与实现类

/*** UserFeedbackService.java* * @author Zero*/
public interface UserFeedbackService {String sendFeedbackEmail(UserFeedbackFormDto formDto);
}
/*** UserFeedbackServiceImpl.java* * @author Zero*/
@Service("userFeedbackService")
public class UserFeedbackServiceImpl implements UserFeedbackService {@Overridepublic String sendFeedbackEmail(UserFeedbackFormDto formDto) {//创建handler对象,调用其hander方法处理具体业务SendFeedbackEmailHandler handler = new SendFeedbackEmailHandler(formDto);return handler.handle();}
}

Handler业务处理类

/*** SendFeedbackEmailHandler.java* * @author Zero*/
public class SendFeedbackEmailHandler {private static final Logger LOG = LoggerFactory.getLogger(SendFeedbackEmailHandler.class);private static final String SUCCESS_RESULT = "1";private static final String SUBJECT = "有新的待处理留言信息";//TEMPLATE为反馈邮件发送模板private static final String TEMPLATE = "template/zh_feedback_root_notice.html";private transient UserFeedbackRepository userFeedbackRepository = BeanProvider.getBean(UserFeedbackRepository.class);private transient MailRepository mailRepository = BeanProvider.getBean(MailRepository.class);private UserFeedbackFormDto formDto;public SendFeedbackEmailHandler(UserFeedbackFormDto formDto) {this.formDto = formDto;}public String handle() {//将留言写入数据库UserFeedback userFeedback = newUserFeedback();userFeedbackRepository.saveUserFeedback(userFeedback);//记录日志AuditLog.create("添加留言(fullName = " + userFeedback.fullName() + ", uuid = " + userFeedback.uuid() + ")");LOG.debug("{}|Save Feedback : {}", WebUtils.getIp(), userFeedback);//邮件反馈sendNoticeEmailToRoot(userFeedback);return SUCCESS_RESULT;}private UserFeedback newUserFeedback() {return new UserFeedback().fullName(formDto.getFullName()).position(formDto.getPosition()).phone(formDto.getPhone()).contentType(formDto.getContentType()).content(formDto.getContent());}//发送邮件的具体实现protected void sendNoticeEmailToRoot(UserFeedback userFeedback) {final IDPConfiguration idpConfiguration = IDPHolder.idpConfiguration();//rootEmailAddressList<String> emails = idpConfiguration.rootEmailList();if (null == emails || emails.size() < 1) {LOG.debug("{}| Not Found EmailAddress: {}", SecurityUtils.username(), emails);return;}Map<String, Object> params = new HashMap<>();params.put("fullName", userFeedback.fullName());params.put("position", userFeedback.position());params.put("phone", userFeedback.phone());params.put("contentType", userFeedback.contentType().getLabel());params.put("content", userFeedback.content());params.put("hostUrl", Holder.host() + "login");STRender render = new STRender(TEMPLATE, params);String content = render.render();for (String email : emails) {//MailTransmitter为邮件发送器MailTransmitter mailTransmitter = new MailTransmitter().subject(SUBJECT).to(email).content(content);final MailTransmitResult result = mailRepository.sendMail(mailTransmitter);AuditLog.createMailLog(email, SUBJECT + "{发送结果:" + result + "}", "来自 " + userFeedback.fullName() + " 的" + userFeedback.contentType().getLabel() + "留言信息需要处理");}}
}

数据持久层

Repository接口

/*** UserFeedbackRepository.java* * @author Zero*/
public interface UserFeedbackRepository {void saveUserFeedback(UserFeedback userfeedback);List<UserFeedback> findUserFeedbackList(Map<String,Object> map);long totalUserFeedbackList(Map<String,Object> map);
}

Repository实现类

/*** UserFeedbackRepositoryMongoDB.java* * @author Zero*/
@Repository("userFeedbackRepository")
public class UserFeedbackRepositoryMongoDB  extends AbstractMongoSupport implements UserFeedbackRepository {@Overridepublic void saveUserFeedback(UserFeedback userfeedback) {this.mongoTemplate().save(userfeedback);}@Overridepublic List<UserFeedback> findUserFeedbackList(Map<String, Object> map) {Query query = addPagination(new Query(),map);addFeedbackConditions(query,map);return this.mongoTemplate().find(query,UserFeedback.class);}private void addFeedbackConditions(Query query, Map<String, Object> map) {String enterpriseName = (String)map.get("enterpriseName");String content = (String)map.get("content");if(StringUtils.isNotEmpty(enterpriseName)){addRegexCriteria(query,"enterpriseName",enterpriseName);}if(StringUtils.isNotEmpty(content)){addRegexCriteria(query,"content",content);}query.with(new Sort(new Sort.Order[]{new Sort.Order(Sort.Direction.DESC, "createTime")}));}@Overridepublic long totalUserFeedbackList(Map<String, Object> map) {Query query = addPagination(new Query(),map);addFeedbackConditions(query,map);return this.mongoTemplate().count(query, UserFeedback.class);}
}

前端页面渲染

JSP页面表单

//contast.jsp
<form:form commandName="formDto" action="${contextPath}/contact/feedback_form" cssClass="pubform ess-form"><input type="hidden" name="forward" value="${contextPath}/contact"><%--<tags:csrf/>--%><div class="input-box"><form:input path="fullName" placeholder="请输入姓名" required="true"/><form:errors path="fullName" cssClass="label text-danger"/></div><div class="input-box"><form:input path="position" placeholder="请输入职位" required="true"/><form:errors path="position" cssClass="label text-danger"/></div><div class="input-box"><form:input path="phone" placeholder="请输入手机号码" required="true"/><span class="err errphone text-danger" style="display: block;"><form:errors path="phone"/></span></div><div class="input-box"><form:select path="contentType" required="true"><form:options items="${formDto.feedbackTypes}" itemLabel="label"/></form:select><form:errors path="contentType" cssClass="label text-danger"/></div><div class="input-box tex-box"><form:textarea path="content" placeholder="请输入留言" required="true"/><form:errors path="content" cssClass="label text-danger"/></div><div class="input-group input-box idencode-box"><form:input path="captcha" onkeyup="value=value.replace(/[^\w\.\/]/ig,'')" name="captcha"class="form-control" maxlength="4" placeholder="请输入验证码" autocomplete="off" required="true"/><span class="input-group-addon input-sm"><img src="${pageContext.request.contextPath}/public/captcha.pngx" onclick="this.src = this.src+'?'" alt="Captcha" style="margin: -2px;"/></span><span class="err" style="display: block;"><form:errors path="captcha" cssClass="label text-danger"/></span></div><div class="input-box sub-box"><input type="submit" name="submit" id="submit" value="提交"/></div><c:if test="${param.contactResult eq '1'}"><div class="success-box" id="connectSuccess"><div class="bg"><span class="gou">✔</span></div><div class="tit-success">提交成功</div><p class="des-success">感谢您的关注。</p><p class="tit-success" style="font-size: 16px"><span id="closeTime">3</span>秒后自动关闭</p></div></c:if></form:form>

JS页面渲染

//contact.js
var Contact = {init: function () {this.evBind();},evBind: function () {var self = this;self.connectSuccessHide();$('#phone').on('blur',function(){self.testTel($(this).val(),$('.errphone'))})},testTel: function (val, err) {var flag = false;if (!this.checkIdentity(val)) {err.html('请输入正确格式的手机号');flag=true;} else {flag=false;err.html('');}return flag},checkIdentity: function (val) {return (/^1[34578]\d{9}$/.test(val));},connectSuccessHide:function(){var time = 3;var closeTimer =  setInterval(function(){time--;if(time==0){clearInterval(closeTimer);$('#connectSuccess').slideUp(400)}$('#closeTime').html(time);},1000)}}$(function(){Contact.init();
})

转载于:https://www.cnblogs.com/zero4869/p/7144016.html

在Spring MVC框架下利用RESTful API和MongoDB实现用户留言与邮件反馈相关推荐

  1. .NET, MVC框架下利用html, CSS,js实现弹出窗口

    在前端UI交互过程中,经常会碰到需要弹出对话框的情况.通过html+css+js来自定义对话框是一个不错的方法. 1. 在HTML中,定义一个DIV. 1.1 将Style设置为 display:no ...

  2. Spring mvc框架下使用kaptcha生成验证码

    1.下载jar包并导入. kaptcha-2.3.2.jar 2.spring 配置文件 applicationContext.xml. <bean id="captchaProduc ...

  3. 搭建基于spring MVC框架 + RESTful架构风格技术总结

    2019独角兽企业重金招聘Python工程师标准>>> 实战篇: 在SpringMVC框架中搭建RESTful架构风格来完成客户端与服务器端的低耦合度.可扩展性.高并发与大数据流量的 ...

  4. RESTful风格(使用Ajax+Spring MVC框架实现)

    RESTful简介: (详情参考:) http://baike.baidu.com/link?url=1FMTyxYwnN5OED7oXwbLBI1z35JCuE1bfIamqJMrbBUeNDPmQ ...

  5. 【Java学习路线之JavaWeb】Spring MVC框架入门教程

    文章目录 读者 阅读条件 MVC设计模式简介 JSP+JavaBean Servlet+JSP+JavaBean MVC优缺点 优点 缺点 Spring MVC是什么 Spring MVC优点 第一个 ...

  6. Mybatis,Spring,MVC框架

    文章目录 @[toc] unit12-mybatis框架 MyBatis简介(了解) 什么是MyBatis 为什么要使用MyBatis MyBatis快速入门 准备数据,创建库和表 创建工程,导入所需 ...

  7. 从 0 开始手写一个 Spring MVC 框架,向高手进阶

    转载自   从 0 开始手写一个 Spring MVC 框架,向高手进阶 Spring框架对于Java后端程序员来说再熟悉不过了,以前只知道它用的反射实现的,但了解之后才知道有很多巧妙的设计在里面.如 ...

  8. local tomcat 找不到springmvc里的包_唰唰的手撕一个简单的Spring Mvc 框架

    @[TOC] 自定义实现Spring Mvc框架 前言 在使用Spring Mvc时候我们需要配置一个中央处理器DispatcherServlet用于分发请求,根据url查找处理器,然后再根据处理器 ...

  9. 自己手写一个Spring MVC框架

    想要了解Spring MVC框架的原理,探究框架是如何设计的,不错的学习方式是阅读源码,然后自己手写一个框架.本文带领大家简化的手写一个Spring MVC框架. Spring框架对于Java后端程序 ...

最新文章

  1. VASP载流子有效质量计算
  2. 【语言处理与Python】1.5自动理解自然语言
  3. 处理WinForm多线程程序时的陷阱(摘自网络)
  4. Oracle数据库的备份
  5. Python 基础入门--简介和环境配置
  6. springboot日志配输出路径配置_Spring Boot 日志配置方法(超详细)
  7. 基线是什么意思_CAD都玩不溜,还好意思说自己搞工程的?
  8. oracle Interval 分区维护与管理要点
  9. c语言strTrimed函数用法介绍,linux type命令用法_转
  10. 第十一章 策略梯度(Policy Gradient)-强化学习理论学习与代码实现(强化学习导论第二版)
  11. 非常逆天的六款Photoshop插件!
  12. 网络安全——钓鱼邮件和网站克隆
  13. opencms mysql_IDO分享 | 如何在centos下安装OpenCMS
  14. GroupByKey VS ReduceByKey
  15. android系统定制添加分辨率,density设置
  16. 2021年最新总结,腾讯、阿里、美团、百度、字节跳动、京东等技术面试题,以及答案,专家出题人分析汇总。持续更新中。
  17. Java应用CPU占用过高问题排查
  18. MMORPG游戏AOI解决方案
  19. Python——变量和简单类型(下篇)
  20. 几个焦耳-汤姆逊(Joule-Thomson)系数的证明题

热门文章

  1. 内部总线、系统总线、外部总线区别
  2. 16个小技巧让你每天都进步(附:提高效率的100条建议)
  3. MySQL - 用户管理
  4. Android studio下载及安装方法
  5. postfix+extmail邮件系统完整安装
  6. 2020中兴开发岗笔试题
  7. linux mock 使用
  8. 四种不同单源最短路径算法性能比较
  9. 大厂二面:应对千亿级高并发场景,MySQL如何分库分表?
  10. CFile记录日志——写各种数据类型的日志(CFile读写包括编码UTF-8)