Dva员工增删改查Demo实现-优化
(后台&)
后台&
springBoot连接数据库,springBoot配置mybatis,springBoot整合日志,开启swagger
##数据源地址
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:postgresql://127.0.0.1:5432/postgres
username: postgres
password: 123456
driverClassName: org.postgresql.Driver
initialSize: 1
maxActive: 20
maxWait: 60000
application:
name: demo-service
##启用Mybatis
orm:
mybatis:
only: true
#mybatis
mybatis-plus:
mapper-locations: classpath:/mapper/*.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.huawei.model
global-config:
#主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
id-type: 2
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
field-strategy: 2
#驼峰下划线转换
db-column-underline: true
#刷新mapper 调试神器
refresh-mapper: true
#数据库大写下划线转换
#capital-mode: true
#序列接口实现类配置
#key-generator: com.baomidou.springboot.xxx
#逻辑删除配置
#logic-delete-value: 0
#logic-not-delete-value: 1
#自定义填充策略接口实现
#meta-object-handler: com.baomidou.springboot.xxx
#自定义SQL注入器
#sql-injector: com.baomidou.springboot.xxx
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
## 服务器端口,自行设置
server:
port: 1111
## 服务注册中心地址
eureka:
instance:
status-page-url-path: /swagger-ui.html
## 日志
logging:
config: classpath:logback.xml
level:
root: debug
platform:
url: http://10.0.7.128:8080
##swagger配置
swagger:
##是否开启swagger文档
enable: true
##网关
host: 10.0.7.128:8080
##接口包(多个用,隔开)
basePackage: com.huawei.controller
##文档标题
title: 示例
##文档描述
description: 变更管理的功能
##文档版本
version: 1.0
logback.xml
%d %p (%file:%line\)- %m%n
UTF8
basedata_log/basedata.log
basedata_log/basedata.log.%d.%i
64 MB
%d %p (%file:%line\)- %m%n
UTF-8
@MapperScan扫描接口
package com.huawei;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
@MapperScan("com.huawei.**.mapper")
public class ServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
@RequestMapping("/index")
String index(){
return "Hello Basedata";
}
}
Restful接口API,swagger使用指南,返回状态类型数据responseUtil
package com.huawei.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huawei.common.util.KeyUtil;
import com.huawei.common.util.PageUtil;
import com.huawei.common.util.RequestMessage;
import com.huawei.common.util.ResponseUtil;
import com.huawei.model.vo.PageBean;
import com.huawei.model.vo.Puser;
import com.huawei.model.vo.PuserVo;
import com.huawei.service.PuserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@RestController
@EnableSwagger2
@Api(value = "用户Controller", tags = { "用户访问接口" })
@RequestMapping("/api")
public class PuserController {
@Resource
private PuserService puserService;
@ApiOperation(value = "测试接口")
@RequestMapping("/users/test")
public PageBean getParamsTest(HttpServletRequest request) throws IOException {
String field = request.getParameter("field");
String keyword = request.getParameter("keyword");
ObjectMapper mapper = new ObjectMapper();
String s = "{\"total\":3,\"current\":1,\"list\":[{\"id\":1,\"name\":\"张三\",\"age\":23,\"sex\":\"女\",\"address\":\"成都\"},{\"id\":2,\"name\":\"李四\",\"age\":24,\"sex\":\"男\",\"address\":\"杭州\"},{\"id\":3,\"name\":\"王五\",\"age\":25,\"sex\":\"男\",\"address\":\"上海\"}]}";
if(StringUtils.isNotBlank(field)){
s = "{\"total\":3,\"current\":1,\"list\":[{\"id\":1,\"name\":\"张三111111\",\"age\":23,\"sex\":\"女\",\"address\":\"成都\"},{\"id\":2,\"name\":\"李四\",\"age\":24,\"sex\":\"男\",\"address\":\"杭州\"},{\"id\":3,\"name\":\"王五\",\"age\":25,\"sex\":\"男\",\"address\":\"上海\"}]}";
}
return mapper.readValue(s,new TypeReference>(){});
}
@ApiOperation(value = "用户查询接口")
@PostMapping(value = {"/users/query","/users/query/{current}"})
public Object usersFuzzyQuery(@PathVariable(required = false) String current,@RequestBody PuserVo puserVo) {
Puser puser = new Puser();
String field = puserVo.getField();
String keyword = puserVo.getKeyword();
if(StringUtils.isBlank(current)||"undefined".equals(current)){
current="1";
}
if(StringUtils.isNotBlank(field)&&StringUtils.isNotBlank(keyword)){
if("name".equals(field)){
puser.setName(keyword);
}
if("address".equals(field)){
puser.setAddress(keyword);
}
}
PageUtil result;
try {
result = puserService.usersFuzzyQuery(puser, Integer.valueOf(current));
} catch (Exception e) {
e.printStackTrace();
return ResponseUtil.failedResponse("查询异常",e.getMessage());
}
return ResponseUtil.successListResponse(result);
}
@ApiOperation(value = "创建用户接口")
@PostMapping("/users/create")
public RequestMessage createUser(@ApiParam("用户实体对象")@RequestBody Puser puser) {
int fid = KeyUtil.genUniqueKey();
puser.setId(fid);
try {
puserService.addUsers(puser);
} catch (Exception e) {
return ResponseUtil.failedResponse("创建异常", e.getMessage());
}
return ResponseUtil.successResponse("创建成功");
}
@ApiOperation(value = "修改用户接口")
@PutMapping("/users/update")
public RequestMessage updateUser(@ApiParam("用户实体对象")@RequestBody Puser puser) {
try {
puserService.updateUser(puser);
} catch (Exception e) {
return ResponseUtil.failedResponse("修改异常", e.getMessage());
}
return ResponseUtil.successResponse("修改成功");
}
@ApiOperation(value = "删除用户接口")
@ApiImplicitParam(name = "ids", value = "要删除用户的id", dataType = "String", paramType = "path", required = true)
@DeleteMapping("/users/delete/{ids}")
public RequestMessage deleteUsers(@PathVariable("ids") String ids) {
if(ids != null){
if(ids.contains(",")){
String[] arrayIds = ids.split(",");
List idList = new ArrayList<>();
for(String id:arrayIds){
idList.add(Integer.valueOf(id));
}
try {
puserService.deleteBatchUsers(idList);
} catch (Exception e) {
return ResponseUtil.failedResponse("删除异常", e.getMessage());
}
}else{
try {
puserService.deleteUser(Integer.valueOf(ids));
} catch (Exception e) {
return ResponseUtil.failedResponse("删除异常", e.getMessage());
}
}
}
return ResponseUtil.successResponse("删除成功");
}
}
package com.huawei.common.util;
public class RequestMessage {
/* 服务器成功返回用户请求数据的状态码 */
public static String SUCCESS_GETS_CODE = "200";
/* 服务器成功返回用户请求数据的提示信息 */
public static String SUCCESS_GETS_MSG = "ok";
/* 新建或修改数据成功返回状态码 */
public static String SUCCESS_POSTS_CODE = "201";
/* 新建或修改数据成功返回提示信息 */
public static String SUCCESS_POSTS_MSG = "ok";
/* 请求进入后台排队(异步请求)成功状态码 */
public static String SUCCESS_ACCEPTED_CODE = "202";
/* 请求进入后台排队(异步请求)成功提示信息 */
public static String SUCCESS_ACCEPTED_MSG = "Accepted";
/* 删除数据成功返回状态码 */
public static String SUCCESS_DELETES_CODE = "204";
/* 删除数据成功返回提示信息 */
public static String SUCCESS_DELETES_MSG = "ok";
/* 服务器发生错误状态码 */
public static String ERROR_CODE = "500";
/* 服务器发生错误提示信息 */
public static String ERROR_MSG = "error";
/* 状态码 */
private String code;
/* 提示信息 */
private String message;
/* 服务器异常信息 */
private String error;
/* 成功返回的数据 */
private Object data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
package com.huawei.common.util;
import java.util.List;
/**
* 接口响应数据封装工具类
* @author zhujindan
*
*/
public class ResponseUtil {
/**
* 操作成功,返回没有分页的列表
* @param records
* @return
*/
public static RequestMessage successListResponse(List records) {
RequestMessage message = new RequestMessage();
message.setCode(RequestMessage.SUCCESS_GETS_CODE);
message.setMessage(RequestMessage.SUCCESS_GETS_MSG);
message.setData(records);
return message;
}
/**
* 操作成功,返回有分页的列表
* @param
* @return
*/
public static PageInfo successListResponse(PageInfo page) {
page.setCode(RequestMessage.SUCCESS_GETS_CODE);
page.setMessage(RequestMessage.SUCCESS_GETS_MSG);
return page;
}
/**
* 操作成功,返回有分页的列表
* @param
* @return
*/
public static PageUtil successListResponse(PageUtil page) {
page.setCode(RequestMessage.SUCCESS_GETS_CODE);
page.setMessage(RequestMessage.SUCCESS_GETS_MSG);
return page;
}
/**
* 操作成功,返回单个对象
* @param obj
* @return
*/
public static RequestMessage successObjectResponse(Object obj){
RequestMessage message = new RequestMessage();
message.setCode(RequestMessage.SUCCESS_GETS_CODE);
message.setMessage(RequestMessage.SUCCESS_GETS_MSG);
message.setData(obj);
return message;
}
/**
* 操作成功,只返回结果,没有记录
* @return
*/
public static RequestMessage successResponse(String msg) {
RequestMessage message = new RequestMessage();
message.setCode(RequestMessage.SUCCESS_GETS_CODE);
if(null == msg || "".equals(msg)){
message.setMessage(RequestMessage.SUCCESS_GETS_CODE);
}else{
message.setMessage(msg);
}
return message;
}
/**
* 操作成功,只返回结果,没有记录(查询数据)
* @return
*/
public static RequestMessage successResponseGets(String msg) {
RequestMessage message = new RequestMessage();
message.setCode(RequestMessage.SUCCESS_GETS_CODE);
if(null == msg || "".equals(msg)){
message.setMessage(RequestMessage.SUCCESS_GETS_CODE);
}else{
message.setMessage(msg);
}
return message;
}
/**
* 操作成功,只返回结果,没有记录(新建或修改)
* @return
*/
public static RequestMessage successResponsePosts(String msg) {
RequestMessage message = new RequestMessage();
message.setCode(RequestMessage.SUCCESS_POSTS_CODE);
if(null == msg || "".equals(msg)){
message.setMessage(RequestMessage.SUCCESS_POSTS_MSG);
}else{
message.setMessage(msg);
}
return message;
}
/**
* 操作成功,只返回结果,没有记录(删除)
* @return
*/
public static RequestMessage successResponseDelete(String msg) {
RequestMessage message = new RequestMessage();
message.setCode(RequestMessage.SUCCESS_DELETES_CODE);
if(null == msg || "".equals(msg)){
message.setMessage(RequestMessage.SUCCESS_DELETES_MSG);
}else{
message.setMessage(msg);
}
return message;
}
/**
* 操作失败,返回错误描述
* @param msg
* @return
*/
public static RequestMessage failedResponse(String msg,String error) {
RequestMessage message = new RequestMessage();
message.setCode(RequestMessage.ERROR_CODE);
if(null == msg || "".equals(msg)){
message.setMessage(RequestMessage.ERROR_MSG);
}else{
message.setMessage(msg);
}
message.setError(error);
return message;
}
}
后台cors跨域处理
package com.huawei.common.util;
import org.apache.catalina.filters.RemoteIpFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
@Bean
public RemoteIpFilter remoteIpFilter(){
return new RemoteIpFilter();
}
@Bean
public CorsFilter corsFilter(){
// SpringMvc 提供了 CorsFilter 过滤器
// 初始化cors配置对象
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 允许跨域的域名,如果要携带cookie,不要写*,*:代表所有域名都可以跨域访问
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.setAllowCredentials(true); // 设置允许携带cookie
corsConfiguration.addAllowedMethod("*"); // 代表所有的请求方法:GET POST PUT DELETE...
corsConfiguration.addAllowedHeader("*"); // 允许携带任何头信息
//初始化cors配置源对象
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**",corsConfiguration);
// 返回corsFilter实例,参数:cors配置源对象
return new CorsFilter(corsConfigurationSource);
}
@Bean
public FilterRegistrationBean testFilterRegistration(){
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/*");
registration.addInitParameter("paramName","paramValue");
registration.setName("MyFilter");
registration.setOrder(1);
return registration;
}
public class MyFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) servletResponse;
HttpServletRequest req = (HttpServletRequest) servletRequest;
String origin = req.getHeader("Origin");
if (!org.springframework.util.StringUtils.isEmpty(origin)) {
//带cookie的时候,origin必须是全匹配,不能使用*
res.addHeader("Access-Control-Allow-Origin", origin);
}
res.addHeader("Access-Control-Allow-Methods", "*");
String headers = req.getHeader("Access-Control-Request-Headers");
// 支持所有自定义头
if (!org.springframework.util.StringUtils.isEmpty(headers)) {
res.addHeader("Access-Control-Allow-Headers", headers);
}
res.addHeader("Access-Control-Max-Age", "3600");
// enable cookie
res.addHeader("Access-Control-Allow-Credentials", "true");
filterChain.doFilter(req, res);
}
@Override
public void destroy() {
Map map = new HashMap();
}
}
}
mybatis的分页处理,mybatis接口接受多个参数,resultMap,mybatisPlus模糊查询使用,@Service,@Repository
package com.huawei.common.util;
import java.util.List;
public class PageUtil {
private int currentPageNum; //当前要看哪一页
private int pageSize=10;//每页显示的条数
private int totalSize;//总记录条数
private int startIndex;//查询开始记录的索引 limit ? ?
private int totalPageNum;//总页数
private int prePageNum;//上一页
private int nextPageNum;//下一页
private List records;//当前页的记录集
private List totalRecords;//所有页的记录集
//用于显示页面上的导航的页号 用户可自定义
private int startPageNum;
private int endPageNum;
private String url;
/* 状态 */
private String code;
/* 返回信息描述 */
private String message;
//使用构造方法,传递必要的两个参数.第一个是页码,第二个总记录条数
public PageUtil(int currentPageNum,int totalSize)
{
this.currentPageNum=currentPageNum;
this.totalSize=totalSize;
//计算开始记录索引
startIndex=(currentPageNum-1)*pageSize;
//计算总页数
totalPageNum=totalSize%pageSize==0?totalSize/pageSize:totalSize/pageSize+1;
//计算开始和结束页号 这个根据自身可设计
if(totalPageNum>9)
{
startPageNum=currentPageNum-4;
endPageNum=currentPageNum+4;
if(startPageNum<1)
{
startPageNum=1;
endPageNum=startPageNum+8;
}
if(endPageNum>totalPageNum)
{
endPageNum=totalPageNum;
startPageNum=endPageNum-8;
}
}
else
{
startPageNum=1;
endPageNum=totalPageNum;
}
}
public int getStartPageNum() {
return startPageNum;
}
public void setStartPageNum(int startPageNum) {
this.startPageNum = startPageNum;
}
public int getEndPageNum() {
return endPageNum;
}
public void setEndPageNum(int endPageNum) {
this.endPageNum = endPageNum;
}
public int getPrePageNum() {
prePageNum=currentPageNum-1;
if(prePageNum<=0)
{
prePageNum=1;
}
return prePageNum;
}
public int getNextPageNum() {
nextPageNum=currentPageNum+1;
if(nextPageNum>totalPageNum)
{
nextPageNum=totalPageNum;
}
return nextPageNum;
}
public int getCurrentPageNum() {
return currentPageNum;
}
public void setCurrentPageNum(int currentPageNum) {
this.currentPageNum = currentPageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalSize() {
return totalSize;
}
public void setTotalSize(int totalSize) {
this.totalSize = totalSize;
}
public int getStartIndex() {
return startIndex;
}
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
public int getTotalPageNum() {
return totalPageNum;
}
public void setTotalPageNum(int totalPageNum) {
this.totalPageNum = totalPageNum;
}
public List getRecords() {
return records;
}
public void setRecords(List records) {
this.records = records;
}
public void setPrePageNum(int prePageNum) {
this.prePageNum = prePageNum;
}
public void setNextPageNum(int nextPageNum) {
this.nextPageNum = nextPageNum;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public List getTotalRecords() {
return totalRecords;
}
public void setTotalRecords(List totalRecords) {
this.totalRecords = totalRecords;
}
public String getCode() {
return code;
}
public String getMessage() {
return message;
}
public void setCode(String code) {
this.code = code;
}
public void setMessage(String message) {
this.message = message;
}
}
package com.huawei.model.vo;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import java.io.Serializable;
@TableName("p_user")
public class Puser implements Serializable {
@TableId("fid")
private Integer fid;
private String name;
private String sex;
private Integer age;
private String address;
public Puser() {
}
public Puser(Integer fid, String name, String sex, Integer age, String address) {
this.fid = fid;
this.name = name;
this.sex = sex;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public Integer getId() {
return fid;
}
public String getSex() {
return sex;
}
public Integer getAge() {
return age;
}
public String getAddress() {
return address;
}
public void setId(Integer fid) {
this.fid = fid;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setAge(Integer age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
}
package com.huawei.model.vo;
import java.io.Serializable;
public class PuserVo implements Serializable {
private Integer fid;
private String name;
private String sex;
private Integer age;
private String address;
private String field;
private String keyword;
public PuserVo(Integer fid, String name, String sex, Integer age, String address, String field, String keyword) {
this.fid = fid;
this.name = name;
this.sex = sex;
this.age = age;
this.address = address;
this.field = field;
this.keyword = keyword;
}
public PuserVo() {
}
public Integer getFid() {
return fid;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public Integer getAge() {
return age;
}
public String getAddress() {
return address;
}
public String getField() {
return field;
}
public String getKeyword() {
return keyword;
}
public void setFid(Integer fid) {
this.fid = fid;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setAge(Integer age) {
this.age = age;
}
public void setAddress(String address) {
this.address = address;
}
public void setField(String field) {
this.field = field;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
}
package com.huawei.service;
import com.huawei.common.util.PageUtil;
import com.huawei.model.vo.Puser;
import java.util.List;
import java.util.Map;
public interface PuserService {
//List usersFuzzyQuery(Puser puser);
PageUtil usersFuzzyQuery(Puser puser, Integer current);
void addUsers(Puser puser);
Integer updateUser(Puser puser);
Integer deleteUser(Integer id);
Map getTotalRecords(Puser puser);
Integer deleteBatchUsers(List idList);
}
package com.huawei.service.impl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.huawei.common.util.PageUtil;
import com.huawei.mapper.PuserMapper;
import com.huawei.model.vo.Puser;
import com.huawei.service.PuserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class PuserServiceImpl extends ServiceImpl implements PuserService {
@Resource
private PuserMapper puserMapper;
@Override
public PageUtil usersFuzzyQuery(Puser puser, Integer currentPageNum) {
Map totalData = getTotalRecords(puser);
Integer totalCount = (Integer) totalData.get("totalCount");
List totalRecords = (List) totalData.get("totalRecords");
PageUtil pu= new PageUtil<>(currentPageNum, totalCount);
List users= puserMapper.usersFuzzyQuery(puser,pu.getStartIndex());
pu.setRecords(users);
pu.setTotalRecords(totalRecords);
return pu;
}
@Override
public void addUsers(Puser puser) {
this.insert(puser);
}
@Override
public Integer updateUser(Puser puser) {
return puserMapper.updateById(puser);
}
@Override
public Integer deleteUser(Integer id) {
return puserMapper.deleteById(id);
}
@Override
public Map getTotalRecords(Puser puser) {
EntityWrapper wrapper = new EntityWrapper<>();
if(StringUtils.isNotBlank(puser.getName())){
wrapper.like("name", puser.getName());
}
if(StringUtils.isNotBlank(puser.getAddress())){
wrapper.like("address", puser.getAddress());
}
List totalRecords = puserMapper.selectList(wrapper);
Integer totalCount = puserMapper.selectCount(wrapper);
Map map = new HashMap<>();
map.put("totalCount",totalCount);
map.put("totalRecords",totalRecords);
return map;
}
@Override
public Integer deleteBatchUsers(List idList) {
return puserMapper.deleteBatchIds(idList);
}
}
package com.huawei.mapper;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.huawei.model.vo.Puser;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface PuserMapper extends BaseMapper {
List usersFuzzyQuery(@Param("user") Puser puser,@Param("current") Integer current);
void addUsers(Puser puser);
}
(前台&)
前台&
dva入口文件,browserHistory,引入loading插件
import dva from 'dva';
import { browserHistory } from 'dva/router';
import createLoading from 'dva-loading';
// 1. Initialize
const app = dva({
history:browserHistory
});
// 2. Plugins
app.use(createLoading());
// 3. Model
//app.model(require('./models/users/users'));
// 4. Router
app.router(require('./router'));
// 5. Start
app.start('#root');
index.less
全局css样式
html, body, :global(#root) {
height: 100%;
padding:0;
margin:0;
}
router.js
webpack modal按需加载modal
import React from 'react';
import PropTypes from 'prop-types';
import { Router } from 'dva/router';
const registerModel = (app, model) => {
if (!(app._models.filter(m => m.namespace === model.namespace).length === 1)) {
app.model(model);
}
};
const RouterConfig = ({ history, app }) => {
/**
* 添加路由,path是请求路基,name是名称说明
* */
const routes = [
{
path: '/',
name: 'welcome',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('./routes/indexPage/IndexPage'));
});
},
},
{
path: '/users',
name: 'users',
getComponent(nextState, cb) {
require.ensure([], (require) => {
registerModel(app, require('./models/users'));
cb(null, require('./routes/users/UsersPage'));
});
},
},
];
return ;
};
RouterConfig.propTypes = {
history: PropTypes.object,
app: PropTypes.object,
};
export default RouterConfig;
前端跨域设置,package.json
{
"private": true,
"scripts": {
"start": "set BROWSER=none&&set PORT=2222&&roadhog server",
"build": "roadhog build"
},
"engines": {
"install-node": "6.9.2"
},
"dependencies": {
"antd": "^2.12.3",
"antd-iconfont": "^2.10.0",
"axios": "^0.16.2",
"babel-plugin-import": "^1.3.1",
"babel-runtime": "^6.9.2",
"dva": "^1.2.1",
"dva-loading": "^0.2.1",
"jquery": "^3.2.1",
"prop-types": "^15.5.10",
"qs": "^6.5.0",
"react": "^15.4.0",
"react-dom": "^15.4.0",
"underscore": "^1.8.3"
},
"devDependencies": {
"babel-eslint": "^7.1.1",
"babel-plugin-dva-hmr": "^0.3.2",
"babel-plugin-transform-runtime": "^6.9.0",
"babel-plugin-module-resolver": "^2.7.1",
"eslint": "^3.12.2",
"eslint-config-airbnb": "^13.0.0",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jsx-a11y": "^2.2.3",
"eslint-plugin-react": "^6.8.0",
"expect": "^1.20.2",
"husky": "^0.12.0",
"redbox-react": "^1.3.2",
"roadhog": "^0.5.2"
},
"proxy": {
"/api": {
"target": "http://localhost:1111/",
"changeOrigin":true
}
}
}
.roadhogrc
{
"entry": "src/index.js",
"theme": {
"@icon-url": "'~antd-iconfont/iconfont'"
},
"proxy": {
"/api": {
"target": "http://localhost:1111/",
"changeOrigin": true,
"pathRewrite": { "^/api" : "" }
}
},
"env": {
"development": {
"extraBabelPlugins": [
"dva-hmr",
["module-resolver", {
"alias": {
"@": "./src"
}
}],
"transform-runtime",
["import", {
"libraryName": "antd",
"libraryDirectory": "lib",
"style": true
}]
]
},
"production": {
"extraBabelPlugins": [
"transform-runtime",
"dva-hmr",
["module-resolver", {
"alias": {
"@": "./src"
}
}],
["import", {
"libraryName": "antd",
"libraryDirectory": "lib",
"style": true
}]
]
}
}
}
dva的service数据接口,request fetch工具类,Error处理器
request.js
import fetch from 'dva/fetch';
import { notification } from 'antd';
const codeMessage = {
200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。',
202: '一个请求已经进入后台排队(异步任务)。',
204: '删除数据成功。',
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
401: '用户没有权限(令牌、用户名、密码错误)。',
403: '用户得到授权,但是访问是被禁止的。',
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
406: '请求的格式不可得。',
410: '请求的资源被永久删除,且不会再得到的。',
422: '当创建一个对象时,发生一个验证错误。',
500: '服务器发生错误,请检查服务器。',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。',
};
function parseJSON(response) {
return response.json();
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const errortext = codeMessage[response.status] || response.statusText;
notification.error({
message: `请求错误 ${response.status}: ${response.url}`,
description: errortext,
});
const error = new Error(response.statusText);
error.name = response.status;
error.response = response;
throw error;
}
/**
* Requests a URL, returning a promise.
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch"
* @return {object} An object containing either "data" or "err"
*/
export default function request(url, options) {
const defaultOptions = {
mode: 'cors',
};
const mergeOptions = {
...options,
...defaultOptions
};
return fetch(url, mergeOptions)
.then(checkStatus)
.then(parseJSON)
.then((data) => ({ data }))
.catch((err) => ({ err }));
}
commonConstant.js
export const url = "http://127.0.0.1:1111/api";
services/users.js
JSON.stringify,qs.stringify,设置请求头,请求体与请求方式,
import request from '../utils/request';
import qs from 'qs';
import {url} from '../utils/commonConstant';
export async function query(params) {
let queryUrl = `${url}/users/query`
if(JSON.stringify(params) == "{}"){
params = {}
}else{
queryUrl = `${url}/users/query/${params.current}`
}
return request(queryUrl, {
method: 'post',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(params),
});
}
export async function create(params) {
return request(`${url}/users/create`, {
method: 'post',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(params),
});
}
export async function remove(params) {
return request(`${url}/users/delete/${params.id}`, {
method: 'delete',
body: qs.stringify(params),
});
}
export async function update(params) {
return request(`${url}/users/update`, {
method: 'put',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
body: JSON.stringify(params),
});
}
models模型结构,parse(payload)处理查询query中文请求参数,subscriptions监听路由,返回状态码,loading
location获取请求参数与url pathname,setState,select获取当前model的state
models/users.js
import { create, remove, update, query } from '../services/users';
import { parse } from 'qs';
import Utils from '../utils/utils'
export default {
namespace: 'users',
state: {
list: [],
totalRecords: [],
total: null,
field: '', // 搜索框字段
keyword: '', // 搜索框输入的关键字
loading: false, // 控制加载状态
current: 1, // 当前页
currentItem: {}, // 当前操作的用户对象
modalVisible: false, // 弹出窗的显示状态
modalType: 'create', // 弹出窗的类型(添加用户,编辑用户)
pagination: {}, // 分页
selectedRowKeys: [], // 选择行的id
selectedRows: [], // 选择的行
totalPageNum: 1, // 总页数
pageSize: 10, // 每页大小
type: '' // 事件类型
},
effects: {
*query({ payload }, { call, put }) {
yield put({ type: 'setState', payload: { loading: true, payload, type: 'query' } });
const { data } = yield call(query, parse(payload));
if (data && data.code === "200") {
yield put({
type: 'setState',
payload: {
list: data.records,
total: data.totalSize,
current: data.currentPageNum,
totalPageNum: data.totalPageNum,
pageSize: data.pageSize,
totalRecords: data.totalRecords,
pagination: Utils.pagination(data),
loading: false
},
});
}
},
*create({ payload }, { select, call, put }) {
yield put({ type: 'setState', payload: { loading: true, modalVisible: false } });
const totalPageNum = yield select(({ users }) => users.totalPageNum);
const { data } = yield call(create, payload);
if (data.code === "200") {
yield put({
type: 'query',
payload: { current: totalPageNum }
})
yield put({
type: 'setState',
payload: {
field: '',
keyword: '',
loading: false
},
});
}
},
*'delete'({ payload }, { call, put }) {
yield put({ type: 'setState', payload: { loading: true, type: 'delete' } });
const { data } = yield call(remove, { id: payload });
if (data.code === "200") {
yield put({
type: 'query',
payload: {}
})
yield put({
type: 'setState',
payload: {
selectedRowKeys: [],
selectedRows: []
},
});
}
},
*update({ payload }, { select, call, put }) {
yield put({ type: 'setState', payload: { loading: true, modalVisible: false } });
const id = yield select(({ users }) => users.currentItem.id);
const users = yield select(({ users }) => users.list);
const newUser = { ...payload, id };
const { data } = yield call(update, newUser);
if (data.code === "200") {
const newList = users.map(user => {
if (user.id === id) {
return { ...user, ...newUser };
}
return user;
});
yield put({
type: 'setState',
payload: { list: newList, loading: false, currentItem: {}, selectedRowKeys: [], selectedRows: [] },
});
}
},
},
subscriptions: {
setup({ dispatch, history }) {
history.listen(location => {
if (location.pathname === '/users') {
dispatch({
type: 'query',
payload: location.query
});
}
});
},
},
reducers: {
setState(state, action) {
return { ...state, ...action.payload };
}
}
}
路由文件,div引入less样式,antD翻页分页处理,location获取query与hash,payload参数传递
批量删除获取table选取内容selectedRows,Modal确认框
routes/usersPage/UsersPage.jsx
import UserList from '../../components/users/UserList';
import UserSearch from '../../components/users/UserSearch';
import UserModal from '../../components/users/UserModal';
import PropTypes from 'prop-types'
import styles from './Users.less';
import { connect } from 'dva';
import React, { useEffect } from 'react'
import { routerRedux } from 'dva/router';
import { notification, Modal, message } from 'antd';
function Users({ location, dispatch, users }) {
const {
loading, list, totalRecords, pageSize, total, current, field, keyword,
currentItem, modalVisible, modalType, pagination,
selectedRowKeys, selectedRows
} = users;
const userSearchProps = {
field,
keyword,
selectedRows,
onAdd() {
dispatch({
type: 'users/setState',
payload: {
modalType: 'create',
currentItem: {},
modalVisible: true,
type: 'create'
},
});
},
onDetail() {
if (selectedRows.length === 0) {
Modal.info({
title: '信息',
content: '请选择一个用户。'
})
} else if (selectedRows.length > 1) {
notification['warning']({
message: '提示!',
description: '请选择一条要查看的数据。'
});
} else {
dispatch({
type: 'users/setState',
payload: {
modalType: 'detail',
currentItem: selectedRows[0],
modalVisible: true,
type: 'detail'
},
});
}
},
onDelete() {
const ids = selectedRowKeys.join(',');
if (selectedRowKeys.length === 0) {
notification['warning']({
message: '提示!',
description: '请选择要删除的数据。'
});
} else {
Modal.confirm({
title: '删除提示',
content: `您确定要删除这些数据吗?`,
onOk: () => {
dispatch({
type: 'users/delete',
payload: ids,
});
message.success('删除成功');
},
})
}
},
onSearch(fieldsValue) {
dispatch({
type: 'users/query',
payload: fieldsValue,
});
},
};
const userListProps = {
dataSource: list,
total,
loading,
current,
pagination,
selectedRowKeys,
selectedRows,
/*{onPageChange(page) {
dispatch(routerRedux.push({
pathname: '/users',
query: { field, keyword, current:page },
}));},
}*/
//前台分页
/*onPageChange(page) {
dispatch({
type:'users/setState',
payload:{
list: totalRecords.slice((page-1)*pageSize,page*pageSize),
current: page,
pagination : {current: page,pageSize,total,showTotal:()=>{
return `共${total}条`
}}
}
})
},*/
onPageChange(page) {
const { query: params, hash } = location;
dispatch({
type: 'users/query',
payload: {
...params,
current: page
}
})
},
onDeleteItem(id) {
dispatch({
type: 'users/delete',
payload: id,
});
},
onEditItem(item) {
dispatch({
type: 'users/setState',
payload: {
modalType: 'update',
currentItem: item,
modalVisible: true,
type: 'edit'
},
});
},
onSelectedRowKeys(selectedRowKeys, selectedRows) {
dispatch({
type: 'users/setState',
payload: {
selectedRowKeys,
selectedRows,
},
});
}
};
const userModalProps = {
item: modalType === 'create' ? {} : currentItem,
type: modalType,
currentItem,
visible: modalVisible,
onOk(data) {
dispatch({
type: `users/${modalType}`,
payload: data,
});
},
onCancel() {
dispatch({
type: 'users/setState',
payload: { modalVisible: false },
});
}
};
//useEffect(() => { getUsers },[])
return (
{/* 用户筛选搜索框 */}
{/* 用户信息展示列表 */}
{/* 添加用户 & 修改用户弹出的浮层 */}
);
}
Users.propTypes = {
users: PropTypes.object,
location: PropTypes.object,
dispatch: PropTypes.func,
};
const mapStateToProps = ({ users }) => {
return { users };
}
export default connect(mapStateToProps)(Users);
routes/usersPage/Users.less
.normal {
width: 1200px;
margin: 20px auto;
}
PropTypes验证,Table组件,Table组件render处理单元格获取record,Popconfirm确认框,rowSelection多选框
Table单元格居中,table字典转义,pagination分页工具类
components/users/UserList.jsx
// ./src/components/Users/UserList.jsx
import React, { PropTypes } from 'react';
// 采用antd的UI组件
import { Table, Popconfirm, Pagination } from 'antd';
import styles from './UserList.less';
// 采用 stateless 的写法
const UserList = ({
loading,
dataSource,
onPageChange,
onDeleteItem,
onEditItem,
pagination,
onSelectedRowKeys,
selectedRowKeys,
}) => {
const columns = [{
title: '姓名',
dataIndex: 'name',
key: 'name',
render: (text) => {text},
}, {
title: '年龄',
dataIndex: 'age',
key: 'age',
}, {
title: '性别',
dataIndex: 'sex',
key: 'sex',
render(sex) {
return sex == 1 ? '男' : '女'
},
}, {
title: '住址',
dataIndex: 'address',
key: 'address',
}, {
title: '操作',
key: 'operation',
render: (text, record) => (
{ onEditItem(record) }} >编辑
onDeleteItem(record.id)}>
删除
),
}];
//多选框
const rowCheckSelection = {
type: 'checkbox',
selectedRowKeys,
onChange: onSelectedRowKeys
}
return (
record.id}
pagination={false}
rowSelection={rowCheckSelection}
/>
);
}
UserList.propTypes = {
loading: PropTypes.bool,
dataSource: PropTypes.array,
onPageChange: PropTypes.func,
onDeleteItem: PropTypes.func,
onEditItem: PropTypes.func,
pagination: PropTypes.object,
onSelectedRowKeys: PropTypes.array,
selectedRowKeys: PropTypes.array,
};
export default UserList;
components/users/UserList.less
.column-left{
text-align: left;
}
.column-right{
text-align: right;
}
.columnCell{
display: table-cell;
vertical-align: middle;
}
.standardTable {
:global {
.ant-table-thead > tr > th > {
text-align: center;
}
.ant-table-tbody > tr > td {
text-align: center;
}
}
}
utils/utils.js
import React from 'react';
import { Select } from 'antd'
const Option = Select.Option;
export default {
formateDate(time){
if(!time)return '';
let date = new Date(time);
return date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()+' '+date.getHours()+':'+date.getMinutes()+':'+date.getSeconds();
},
pagination(data){
return {
current:data.currentPageNum,
pageSize:data.pageSize,
total: data.totalSize,
showTotal:()=>{
return `共${data.totalSize}条`
},
showQuickJumper:false
}
},
getOptionList(data){
if(!data){
return [];
}
let options = [] //[];
data.map((item)=>{
options.push()
})
return options;
}
}
UserSearch公共查询表单BaseForm,表单查询框样式设置,获取方法中的event,获取form表单的字段,验证字段validateFields
components/users/UserSearch.jsx
import React, { PropTypes } from 'react';
import { Form, Button, Card } from 'antd';
import BaseForm from '../../components/BaseForm'
import styles from './UserSearch.less';
const UserSearch = ({
onSearch,
onAdd,
onDetail,
onDelete,
form: {
validateFields,
},
}) => {
const formList = [
{
type: 'SELECT',
label: '选项',
field: 'field',
placeholder: '',
initialValue: 'name',
width: 80,
list: [{ id: 'name', name: '姓名' }, { id: 'address', name: '住址' }]
},
{
type: 'INPUT',
label: '关键字',
field: 'keyword',
placeholder: '请输入关键字',
width: 80
}
]
function handleFilter(params) {
var event = window.event
event.preventDefault();
validateFields((errors) => {
if (!!errors) {
return;
}
onSearch(params);
});
}
// 操作员工
function handleOperator(type) {
if (type === 'create') {
onAdd();
} else if (type === "edit" || type === 'detail') {
if (type === 'detail') {
onDetail();
}
} else if (type === "delete") {
onDelete();
}
}
return (
);
};
UserSearch.propTypes = {
form: PropTypes.object.isRequired,
onSearch: PropTypes.func,
onAdd: PropTypes.func,
onDetail: PropTypes.func,
onDelete: PropTypes.func
};
export default Form.create()(UserSearch);
components/users/UserSearch.less
.normal {
display: flex;
}
.search {
flex: 1;
}
.operateWrap {
button{
margin-right: 10px;
}
margin-top:20px;
}
getFieldsValue获取表单输入内容,提价表单,重置表单,getFieldDecorator数据双向绑定,设置表单样式style
components/BaseForm/index.js
import React from 'react'
import { Input, Select, Form, Button, Checkbox, Radio, DatePicker} from 'antd'
import Utils from '../../utils/utils';
const FormItem = Form.Item;
const Option = Select.Option;
class FilterForm extends React.Component{
handleFilterSubmit = ()=>{
let fieldsValue = this.props.form.getFieldsValue();
this.props.filterSubmit(fieldsValue);
}
reset = ()=>{
this.props.form.resetFields();
}
initFormList = ()=>{
const { getFieldDecorator } = this.props.form;
const formList = this.props.formList;
const formItemList = [];
if (formList && formList.length>0){
formList.forEach((item,i)=>{
let label = item.label;
let field = item.field;
let initialValue = item.initialValue || '';
let placeholder = item.placeholder;
let width = item.width;
if (item.type == '时间查询'){
const begin_time =
{
getFieldDecorator('begin_time')(
)
}
;
formItemList.push(begin_time)
const end_time =
{
getFieldDecorator('end_time')(
)
}
;
formItemList.push(end_time)
}else if(item.type == 'INPUT'){
const INPUT =
{
getFieldDecorator([field],{
initialValue: initialValue
})(
)
}
;
formItemList.push(INPUT)
} else if (item.type == 'SELECT') {
const SELECT =
{
getFieldDecorator([field], {
initialValue: initialValue
})(
)
}
;
formItemList.push(SELECT)
} else if (item.type == 'CHECKBOX') {
const CHECKBOX =
{
getFieldDecorator([field], {
valuePropName: 'checked',
initialValue: initialValue //true | false
})(
{label}
)
}
;
formItemList.push(CHECKBOX)
}
})
}
return formItemList;
}
render(){
return (
);
}
}
export default Form.create({})(FilterForm);
formItemLayout设置表单标签宽度占比,表单校验,三元表达式只读,Icon,单选框,新增修改显示不同的选择内容
components/users/UserModal.js
import React, { PropTypes } from 'react';
import { Form, Input, Modal, Icon, InputNumber, Radio } from 'antd';
const FormItem = Form.Item;
const RadioGroup = Radio.Group;
const formItemLayout = {
labelCol: {
span: 6,
},
wrapperCol: {
span: 6,
}
};
const formItemAddressLayout = {
labelCol: {
span: 6,
},
wrapperCol: {
span: 14,
}
};
const UserModal = ({
visible,
item = item || {},
type,
onOk,
onCancel,
form: {
getFieldDecorator,
validateFields,
getFieldsValue,
},
}) => {
function handleOk() {
if (type === 'detail') {
onCancel();
} else {
validateFields((errors) => {
if (errors) {
return;
}
const data = { ...getFieldsValue(), id: item.id };
onOk(data);
});
}
}
function checkNumber(rule, value, callback) {
if (!value) {
callback(new Error('年龄必须填写!'));
}
if (!/^[\d]{1,2}$/.test(value)) {
callback(new Error('请输入合法年龄!'));
} else {
callback();
}
}
const modalOpts = {
visible,
onOk: handleOk,
onCancel
};
return (
);
};
UserModal.propTypes = {
visible: PropTypes.any,
form: PropTypes.object,
item: PropTypes.object,
type: PropTypes.string,
onOk: PropTypes.func,
onCancel: PropTypes.func
};
export default Form.create({
mapPropsToFields(props) {
if (props.type === 'create') {
return {
name: {},
age: {},
sex: {},
address: {}
}
}
return {
name: { ...props.item.name },
age: { ...props.item.age },
sex: { ...props.item.sex },
address: { ...props.item.address }
}
}
})(UserModal);
你可能感兴趣的:(全栈前端开发,REACT)