2.1.开发环境检查

  1. 开发工具:SpringToolSuite(STS)、MySql6.0、MySQL Workbench
  2. 检查STS的jdk配置:jdk8
  3. 检查STS的tomcat配置:tomcat8.5
  4. 检查STS的文件编码配置:utf-8

    2.2.搭建javaWeb工程总体架构

    2.2.1.工程类型

    创建工程类型:Dynamic Web project

    2.2.2.导入jar包

  5. mysql-connector-java-bin.jar

  6. jackson-core.jar
  7. jackson-annotations.jar
  8. jackson-databind.jar

    2.2.3.工程目录结构

    02.服务器端项目搭建 - 图1

    2.2.4.MVC架构解决方案

    02.服务器端项目搭建 - 图2

  9. 本工程采用:基于Servlet的简易MVC架构。

  10. 本工程采用:约定优于配置的原则来搭建简易MVC框架。
  11. 本工程中规定:
    请求url与Controller方法映射示例: http://localhost:8080/elm/Controller类名/Controller方法名
  12. 本工程中不需要任何配置文件。

    附录:DispatcherServlet代码:

  1. package com.neusoft.elm.framework;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import javax.servlet.ServletException;
  4. import javax.servlet.annotation.WebServlet;
  5. import javax.servlet.http.HttpServlet;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. import java.io.IOException;
  9. import java.io.PrintWriter;
  10. import java.lang.reflect.Method;
  11. /**
  12. * 自定义前端控制器 拦截url格式要求: /控制器类名/控制器方法名
  13. */
  14. @WebServlet("/")
  15. public class DispatcherServlet extends HttpServlet {
  16. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  17. //中文编码处理
  18. request.setCharacterEncoding("utf-8");
  19. response.setCharacterEncoding("utf-8");
  20. response.setContentType("application/json;charset=utf-8");
  21. //获取客户端请求路径(/HelloController/say)
  22. String path = request.getServletPath();
  23. //根据请求路径,将Controller的类名和方法名解析出来
  24. String className = path.substring(1,path.lastIndexOf("/"));
  25. String methodName = path.substring(path.lastIndexOf("/")+1);
  26. PrintWriter out = null;
  27. //判断请求路径,根据不同的请求,分发给不同的业务处理器
  28. try{
  29. //通过Controller类全名获取此类的所有信息
  30. Class clazz = Class.forName("com.neusoft.elm.controller."+className);
  31. //创建Controller类的对象
  32. Object controller = clazz.newInstance();
  33. //获取Controller类对象中的方法
  34. Method method = clazz.getMethod(methodName,new Class[]{HttpServletRequest.class});
  35. //调用上面获取的方法
  36. Object result = method.invoke(controller,new Object[]{request});
  37. //获取向客户端响应的输出流
  38. out = response.getWriter();
  39. ObjectMapper om = new ObjectMapper();
  40. //向客户端响应json数据
  41. out.print(om.writeValueAsString(result));
  42. }catch(Exception e){
  43. e.printStackTrace();
  44. System.out.println("DispatcherServlet信息:请求url:"+path);
  45. System.out.println("DispatcherServlet信息:类名:"+className+"\t方法名:"+methodName);
  46. }finally {
  47. out.close();
  48. }
  49. }
  50. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  51. doPost(request,response);
  52. }
  53. }

2.2.5.跨域问题解决方案

本工程使用CORS解决前后端分离开发模式时的跨域问题。 CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。 整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。 因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

附录:CORS过滤器代码:

  1. package com.neusoft.elm.filter;
  2. import java.io.IOException;
  3. import javax.servlet.Filter;
  4. import javax.servlet.FilterChain;
  5. import javax.servlet.FilterConfig;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.ServletRequest;
  8. import javax.servlet.ServletResponse;
  9. import javax.servlet.annotation.WebFilter;
  10. import javax.servlet.http.HttpServletResponse;
  11. @WebFilter("/*")
  12. public class CorsFilter implements Filter{
  13. @Override
  14. public void init(FilterConfig filterConfig) throws ServletException { }
  15. @Override
  16. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  17. HttpServletResponse response = (HttpServletResponse) servletResponse;
  18. //注意:这里设置只允许http://localhost:8081进行跨域访问
  19. response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");
  20. response.setHeader("Access-Control-Allow-Credentials", "true");
  21. response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
  22. response.setHeader("Access-Control-Max-Age", "3628800");
  23. response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization");
  24. filterChain.doFilter(servletRequest, servletResponse);
  25. }
  26. @Override
  27. public void destroy() { }
  28. }

2.2.6.事务处理解决方案

首先要明确一点:事务处理放在service层。所以:

  1. Connection的创建与销毁要放在service层。
  2. 为了保证在同一次请求处理的线程中,service层和dao层都共用同一个Connection对象,需要将Connection对象放入ThreadLocal中。service层和dao层使用的Connection对象一律从ThreadLocal获取。
  3. dao层不再处理异常,dao层产生的异常将直接抛给service层进行处理。
  4. dao层负责关闭PreparedStatement和ResultSet,service层负责关闭Connection。

02.服务器端项目搭建 - 图3

附录: ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

DBUtil类代码:

  1. package com.neusoft.elm.util;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.SQLException;
  7. public class DBUtil {
  8. private static final ThreadLocal<Connection> TL = new ThreadLocal<Connection>();
  9. private static final String URL="jdbc:mysql://localhost:3306/elm?characterEncoding=utf-8";
  10. private static final String DRIVER="com.mysql.jdbc.Driver";
  11. private static final String USERNAME="root";
  12. private static final String PASSWORD="123";
  13. // 获取Connection
  14. public static Connection getConnection() {
  15. Connection con = null;
  16. con = TL.get();
  17. if (con==null) {
  18. con = createConnection();
  19. TL.set(con);
  20. }
  21. return con;
  22. }
  23. // 开启一个事务
  24. public static void beginTransaction() throws Exception {
  25. Connection con = null;
  26. con = TL.get();
  27. if (con == null) {
  28. con = createConnection();
  29. TL.set(con);
  30. }
  31. con.setAutoCommit(false);
  32. }
  33. // 提交一个事务
  34. public static void commitTransaction() throws Exception {
  35. Connection con = TL.get();
  36. con.commit();
  37. }
  38. // 回滚一个事务
  39. public static void rollbackTransaction() throws Exception {
  40. Connection con = TL.get();
  41. con.rollback();
  42. }
  43. // 关闭各种资源
  44. public static void close(ResultSet rs, PreparedStatement pst) {
  45. try {
  46. if (rs != null) {
  47. rs.close();
  48. }
  49. if (pst != null) {
  50. pst.close();
  51. }
  52. } catch (SQLException e) {
  53. e.printStackTrace();
  54. }
  55. }
  56. // 关闭各种资源
  57. public static void close(PreparedStatement pst) {
  58. try {
  59. if (pst != null) {
  60. pst.close();
  61. }
  62. } catch (SQLException e) {
  63. e.printStackTrace();
  64. }
  65. }
  66. // 关闭各种资源
  67. public static void close() {
  68. Connection con = TL.get();
  69. try {
  70. if (con != null) {
  71. con.close();
  72. }
  73. //至关重要,否则容易造成内存溢出等问题。
  74. TL.remove();
  75. } catch (SQLException e) {
  76. e.printStackTrace();
  77. }
  78. }
  79. private static Connection createConnection() {
  80. Connection con = null;
  81. if (con == null) {
  82. try {
  83. Class.forName(DRIVER);
  84. con = DriverManager.getConnection(URL, USERNAME, PASSWORD);
  85. } catch (Exception e) {
  86. e.printStackTrace();
  87. }
  88. }
  89. return con;
  90. }
  91. }

dao层代码示例:

  1. @Override
  2. //必须要有: throws Exception
  3. public int saveCart(Cart cart) throws Exception{
  4. int result = 0;
  5. String sql = "insert into cart values(null,?,?,?,1)";
  6. try {
  7. //Connection从ThreadLocal中获取
  8. con = DBUtil.getConnection();
  9. pst = con.prepareStatement(sql);
  10. pst.setInt(1, cart.getFoodId());
  11. pst.setInt(2, cart.getBusinessId());
  12. pst.setString(3, cart.getUserId());
  13. result = pst.executeUpdate();
  14. }finally { //这里不能处理异常,也就是没有catch,只有finally
  15. DBUtil.close(pst); //这里负责关闭PreparedStatement和ResultSet
  16. }
  17. return result;
  18. }

service层代码示例:

  1. @Override
  2. public int createOrders(String userId,Integer businessId,Integer daId) {
  3. try {
  4. DBUtil.beginTransaction(); //开启一个事务
  5. //调用多个Dao进行数据处理
  6. //... ...
  7. //... ...
  8. DBUtil.commitTransaction(); //提交一个事务
  9. } catch (Exception e) {
  10. try {
  11. DBUtil.rollbackTransaction(); //回滚一个事务
  12. } catch (Exception e1) {
  13. e1.printStackTrace();
  14. }
  15. e.printStackTrace();
  16. } finally {
  17. DBUtil.close(); // 关闭Connection
  18. }
  19. return orderId;
  20. }

2.2.7.Servlet返回JSON解决方案

Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。 Jackson 社 区相对比较活跃,更新速度也比较快, 从 Github 中的统计来看,Jackson 是最流行的 json 解析器之一 。 Spring MVC 的默认 json 解析器便是 Jackson。
本项目中,Servlet中使用Jackson将java对象或集合转换为json对象或数组后,返回前端。

  1. ObjectMapper om = new ObjectMapper();
  2. out.print(om.writeValueAsString(result)); //result就是响应数据

2.2.8.AJAX解决方案

由于本项目前端使用Vue框架,所有AJAX采用axios框架(这是尤雨溪推荐使用的)。

  1. this.$axios.post('DeliveryAddressController/saveDeliveryAddress', this.$qs.stringify(
  2. this.deliveryAddress //josn对象类型的提交参数
  3. )).then(response => {
  4. //做响应处理
  5. }).catch(error => {
  6. console.error(error);
  7. });

2.2.9.图片解决方案

对于购物系统来说,商家信息、食品信息中必须要使用大量的图片。
在本工程中,由于使用的图片都比较小,所以采用Base64编码方式来存储图片信息。
Base64是一种用64个字符来表示任意二进制数据的方法。 我们知道,图片就是二进制数据。而Base64就可以将图片的二进制数据转换成字符串形式。这样能让我们方便的在数据库中,对图片进行存储和读取。

  1. <img src="data:image/jpeg;base64,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">

[

](https://null_688_6639.gitee.io/javase/18%E5%89%8D%E5%90%8E%E7%AB%AF%E9%A1%B9%E7%9B%AE/01%E9%A1%B9%E7%9B%AE%E6%A6%82%E8%BF%B0.html)