从0到1完成前后端分离的web项目
最简最少技术栈创建一个完整项目
技术栈:
后端: springboot + mybatis(注解形式)
前端: jquery+layUI
项目启动
创建spring项目
打开idea 点击新建项目,选择spring initializr

一步一步往下填写相关信息,填错了也无所谓,可以复制我的pom文件
pom文件配置
配置mybatis和必要启动组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> <relativePath/> </parent> <groupId>com.dql</groupId> <artifactId>retailmanager</artifactId> <version>0.0.1-SNAPSHOT</version> <name>retailmanager</name> <description>team work</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
</project>
|
配置基础文件结构

数据库配置
选择一个数据库,这里选择mysql,无所谓。
创建utf8的数据库
CREATE DATABASE retail_manager DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
创建用户表
可以用命令行,或者navicate或者idea自带的管理工具


创建实体类和mapper
实体类bean应该遵守阿里的相关约定,dto vo po 以及互相转换的orika
这里推荐选择lombok,这个插件的好处是不用写getter和setter,可以让代码更加精简。
mapper需要配置mapper的resource文件,这个xml文件格式可以百度下,创建xml文件 填入模板
1 2 3 4 5 6
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.yourproject">
</mapper>
|
注意:生成的UserDao里面需要加上@Mapper
注解否则无法被扫描到
创建service
注意sevice层的注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| package com.dql.retailmanager.service;
import com.dql.retailmanager.dao.mapper.UserDao; import com.dql.retailmanager.entity.User; import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service public class UserService { @Resource UserDao userDao;
public User findUserById(int id) { return userDao.selectByPrimaryKey(id); }
public int createUser(User user) { return userDao.insert(user); }
public int deleteUserById(int id) { return userDao.deleteByPrimaryKey(id); }
}
|
创建controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package com.dql.retailmanager.controller;
import com.dql.retailmanager.entity.User; import com.dql.retailmanager.service.UserService; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController @RequestMapping("/user") public class UserController { @Resource UserService userService;
@GetMapping("/getUserById") public User getUserById(@RequestParam int id) { return userService.findUserById(id); }
@GetMapping("/deleteUserById") public int deleteUserById(@RequestParam int id) { return userService.deleteUserById(id); }
@PostMapping("/addUser") public int addUser(@RequestBody User user) { return userService.createUser(user); }
@PostMapping("/updateUser") public int updateUser(@RequestBody User user) { return userService.updateUser(user); } }
|
配置文件配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| server: port: 8081 spring:
datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://47.107.105.158:3306/test?characterEncoding=utf-8&useSSL=false username: root password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
configuration: map-underscore-to-camel-case: true
|
完成启动

测试后台

单点登陆校验
数据库配置session,本地使用localstorage存放sessionid,一般这个单点登录和分布式集群是用redis来管理的,但是这里为了不引入更多技术就用数据库了,问题不大。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| login.js:
import urlInfo from './baseURL.js' $(function () { layui.use('form', function () { var form = layui.form; layer.msg('login system....', function () { form.on('submit(login)', function (data) { var rod = Math.round(1, 100); var md5rod = $.md5(rod + 'author'); console.log(md5rod); $.get(urlInfo.baseUrl + urlInfo.login, { name: data.field.username, pwd: data.field.password, sessionToken: md5rod }, function (data, status) { if (data != null && data != "") { localStorage.setItem("token", md5rod); localStorage.setItem("userId", data.id) localStorage.setItem("user", data); location.href = 'index.html'; } else { alert("error user or password"); $("#login-name").val(""); $("#login-password").val(""); } }); return false; }); });
}); }) check js:
import urlInfo from './baseURL.js' layui.use(['element', 'layer'], function () { var element = layui.element; $.get(urlInfo.baseUrl + urlInfo.sessionCheck, { userId: localStorage.getItem("userId"), token: localStorage.getItem("token") }, function (data, status) { if (data == -1) { layer.msg('please login'); setTimeout(() => { window.location.href = "./login.html"; window.event.returnValue = false; }, 1500); } else { console.log("logined user"); } }); });
|
前后端分离
配置nginx反向代理 解决跨域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
| #user nobody; worker_processes 1;
#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;
#pid logs/nginx.pid;
events { worker_connections 1024; }
http { include mime.types; default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on; #tcp_nopush on;
#keepalive_timeout 0; keepalive_timeout 65;
#gzip on;
server { listen 80; server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / { root html; index index.html index.htm; }
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; }
# proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #}
# deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
# another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias;
# location / { # root html; # index index.html index.htm; # } #}
# HTTPS server # #server { # listen 443 ssl; # server_name localhost;
# ssl_certificate cert.pem; # ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on;
# location / { # root html; # index index.html index.htm; # } #} server{ listen 9999; server_name localhost; location / { proxy_pass http://localhost:8081; } location /user/ { proxy_pass http://localhost:8080; } location /session/ { proxy_pass http://localhost:8080; } }
}
|

执行reload命令生效配置
配置分页器
pom
1 2 3 4 5
| <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.5</version> </dependency>
|
yml
1 2 3 4 5 6
| # pagehelper pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true params: count=countSql
|