1. What is Zoe?
1.1 What Zoyi Can Do
When you are developing an enterprise-level project, in addition to the development of specific business needs provided by users, there are also some general architecture functions
1.2 When is it suitable for use
The function is very simple, providing basic system management, monitoring and code generation.
1.3 What functions does Zoyi provide
1.3.1 System Management
User management: The user is the system operator, and this function mainly completes the system user configuration.
Department management: Configure the system organization (company, department, group), and the tree structure shows the support data permissions.
Position management: configure the positions that system users belong to.
Menu management: configure the system menu, operation authority, button authority identification, etc.
Role management: role menu authority assignment, role setting, data range authority division by organization.
Dictionary management: maintain some relatively fixed data frequently used in the system.
Parameter management: dynamically configure common parameters for the system.
Notification Announcement: The system notifies and announces the release and maintenance of information.
1.3.2 Log Management
Operation log: system normal operation log record and query; system abnormal information log record and query.
Login Logs: System login logging queries contain login exceptions.
1.3.3 System Monitoring
Online users: monitor the status of active users in the current system.
Service monitoring: monitor the current system CPU, memory, disk, stack and other related information.
Cache monitoring: query, view, clear and other operations on the system cache.
Online Builder: Drag form elements to generate corresponding HTML code.
Connection pool monitoring: monitor the status of the current system database connection pool, and analyze SQL to find system performance bottlenecks.
1.3.4 System tools
Scheduled tasks: Online (add, modify, delete) task scheduling includes execution result logs.
Code generation: front-end and back-end code generation (java, html, xml, sql) supports CRUD download.
System interface: automatically generate relevant API interface documents according to the business code.
2. Quick Start Ruoyi
2.1 Front-end construction
npm install
npm run dev
2.2 Backend construction
Trivial, modifying databases and redis.
Run successfully!
3. Code introduction
1.ruoyi-quartz
Using quartz as a timed task management, not much to say here, is a commonplace problem. If you want to know, you can refer to the article: Quartz implements timing tasks
2. ruoyi-generator
This package is a code generator, the main process is as follows.
1.GenTableServiceImpl/generatorCode code generation
The core code is the method of this class. Mainly use the API of org.apache.velocity.app .
@Override
public void generatorCode(String tableName)
{
// 查询表信息
GenTable table = genTableMapper.selectGenTableByName(tableName);
// 设置主子表信息
setSubTable(table);
// 设置主键列信息
setPkColumn(table);
VelocityInitializer.initVelocity();
VelocityContext context = VelocityUtils.prepareContext(table);
// 获取模板列表
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
for (String template : templates)
{
if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm"))
{
// 渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, Constants.UTF8);
tpl.merge(context, sw);
try
{
String path = getGenPath(table, template);
FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
}
catch (IOException e)
{
throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
}
}
}
}
3.ruoyi-system
Standard CRUD method. There is not much to say. But the ruoyi project isolates the controller from the service part.
4.ruoyi-common
1.annotation
Custom annotations, the functions of annotations are below.
2.config
Get the configuration information in application.yml and inject it into the project bean.
3.constant
Provides a constant pool for the project.
4.core
1.controller
The base class of all interface layers provides methods such as paging and sorting, and other interface classes can be directly inherited. Common practice for architecture.
public class BaseController
{
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
*/
@InitBinder
public void initBinder(WebDataBinder binder)
{
// Date 类型转换
binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
{
@Override
public void setAsText(String text)
{
setValue(DateUtils.parseDate(text));
}
});
}
/**
* 设置请求分页数据
*/
protected void startPage()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
{
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
Boolean reasonable = pageDomain.getReasonable();
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
}
}
/**
* 设置请求排序数据
*/
protected void startOrderBy()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
{
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
PageHelper.orderBy(orderBy);
}
}
/**
* 响应请求分页数据
*/
@SuppressWarnings({
"rawtypes", "unchecked" })
protected TableDataInfo getDataTable(List<?> list)
{
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.SUCCESS);
rspData.setMsg("查询成功");
rspData.setRows(list);
rspData.setTotal(new PageInfo(list).getTotal());
return rspData;
}
.
.
.
2.domain
A collection of entity classes used by schema queries such as permissions, which are BaseEntity、AjaxResult
often used for schema design.
BaseEntity needs to be inherited by other entity classes, and provides common fields such as page number and total number.
AjaxResult is an entity class that is returned uniformly, and can agree on a fixed return format with the front desk. {code: message: data}
Format.
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
/** 状态码 */
public static final String CODE_TAG = "code";
/** 返回内容 */
public static final String MSG_TAG = "msg";
/** 数据对象 */
public static final String DATA_TAG = "data";
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult()
{
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public AjaxResult(int code, String msg)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(int code, String msg, Object data)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (StringUtils.isNotNull(data))
{
super.put(DATA_TAG, data);
}
}
.
.
.
public class BaseEntity implements Serializable
{
private static final long serialVersionUID = 1L;
/** 搜索值 */
private String searchValue;
/** 创建者 */
private String createBy;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/** 更新者 */
private String updateBy;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/** 备注 */
private String remark;
/** 请求参数 */
private Map<String, Object> params;
.
.
.
5.enums
Enumeration class, not much to say here.
6.exception
It encapsulates a series of exceptions and can be used in a specific period.
7.filter
Filter, general wording, if you use it, just copy it directly.
8.utils
A large number of tools are provided. It can be directly copied and used if necessary.
5. ruoyi-framework
1.DataScopeAspect
1. DataScopeAspect data permissions
When executing the interface, use AOP to splice the query conditions such as the current user's organization, and you can see the dynamic splicing of SQL statements according to the data permission category maintained on the menu page. The core code is as follows:
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
{
//拼接sql
StringBuilder sqlString = new StringBuilder();
for (SysRole role : user.getRoles())
{
String dataScope = role.getDataScope();
if (DATA_SCOPE_ALL.equals(dataScope))
{
sqlString = new StringBuilder();
break;
}
//自定义权限拼接
else if (DATA_SCOPE_CUSTOM.equals(dataScope))
{
sqlString.append(StringUtils.format(
" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
role.getRoleId()));
}
//部门权限拼接
else if (DATA_SCOPE_DEPT.equals(dataScope))
{
sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
}
//部门及以下权限拼接
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
{
sqlString.append(StringUtils.format(
" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
deptAlias, user.getDeptId(), user.getDeptId()));
}
.
.
.
2.DataSourceAspect multiple data sources
Use the above DataSource annotation to dynamically switch data sources. If there is a need, you can use it directly, and the writing method is fixed.
3. LogAspect log
Collect global logs, such as user name, interface method, calling ip, etc., and insert them into the database to compare common functions.
protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
{
try
{
// 获取当前的用户
LoginUser loginUser = SecurityUtils.getLoginUser();
// *========数据库日志=========*//
SysOperLog operLog = new SysOperLog();
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
operLog.setOperIp(ip);
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
//获取用户姓名
if (loginUser != null)
{
operLog.setOperName(loginUser.getUsername());
}
if (e != null)
{
operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
}
// 设置方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
operLog.setMethod(className + "." + methodName + "()");
// 设置请求方式
operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
// 处理设置注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 保存数据库
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
}
catch (Exception exp)
{
// 记录本地异常日志
log.error("==前置通知异常==");
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
4. RateLimiterAspect current limiting
Store the ip of each call in redis, and then judge the time interval between this call and the last call. A short call blocks the call.
@Before("@annotation(rateLimiter)")
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
{
//redis固定的参数
String key = rateLimiter.key();
int time = rateLimiter.time();
int count = rateLimiter.count();
//获取ip+调用的方法
String combineKey = getCombineKey(rateLimiter, point);
List<Object> keys = Collections.singletonList(combineKey);
try
{
//获取一定时间内的调用次数
Long number = redisTemplate.execute(limitScript, keys, count, time);
if (StringUtils.isNull(number) || number.intValue() > count)
{
throw new ServiceException("访问过于频繁,请稍候再试");
}
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), key);
}
catch (ServiceException e)
{
throw e;
}
catch (Exception e)
{
throw new RuntimeException("服务器限流异常,请稍候再试");
}
}
2.config
1.DruidProperties
Obtain data source information from application.yml. The fixed writing method is not described in detail.
2.ApplicationConfig
Configuring time zone information is not described in detail here.
3.CaptchaConfig
Verification code configuration, configuration text box format, etc., fixed writing.
4.DruidConfig
Multiple data source configuration, fixed writing.
5.FastJson2JsonRedisSerializer
Redis serialization configuration, fixed writing.
6.FilterConfig
Filter configuration, @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
according to whether application.yml is configured with xss.enabled value determines whether to load the class, that is, whether to enable the xss interceptor.
7.KaptchaTextCreator
The rules of verification code verification, here is to calculate the verification code, the logic is in this category, and will not be explained in detail.
8.MyBatisConfig
This class dynamically obtains the address of the mybatis package from application.yml. And repackage SqlSessionFactory. Realize the configurability of mybatis path.
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
{
//从application.yml获取配置
String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
String mapperLocations = env.getProperty("mybatis.mapperLocations");
String configLocation = env.getProperty("mybatis.configLocation");
//获取实体类的包
typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
VFS.addImplClass(SpringBootVFS.class);
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
//加入数据源
sessionFactory.setDataSource(dataSource);
//加入实体类地址
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
//加入mapper
sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
//加入配置文件地址
sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
return sessionFactory.getObject();
}
9.RedisConfig
Redis configuration fixed writing method, if you integrate redis, you can refer to it.
10.ResourcesConfig
General configuration, including interceptor effective configuration, cross-domain configuration, etc. can be used directly.
public class ResourcesConfig implements WebMvcConfigurer
{
@Autowired
private RepeatSubmitInterceptor repeatSubmitInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
/** 本地文件上传路径 */
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
.addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
/** swagger配置 */
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
}
//配置拦截器生效
@Override
public void addInterceptors(InterceptorRegistry registry)
{
//此处配置了上文点击重复的拦截器
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
}
//跨域配置
@Bean
public CorsFilter corsFilter()
{
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
// 设置访问源地址
config.addAllowedOriginPattern("*");
// 设置访问源请求头
config.addAllowedHeader("*");
// 设置访问源请求方法
config.addAllowedMethod("*");
// 有效期 1800秒
config.setMaxAge(1800L);
// 添加映射路径,拦截一切请求
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
// 返回新的CorsFilter
return new CorsFilter(source);
}
}
10 SecurityConfig
Security configuration, if you want to know more about it, please visit the blogger's column: Security entry to proficiency.
11.ServerConfig
Obtain request information, including: domain name, port, context access path
12.ThreadPoolConfig
Thread pool configuration, fixed configuration, where the manager below uses an asynchronous thread pool.
3.datasource
Fixed configuration of multiple data sources, used in conjunction with DataSourceAspect.
4.interceptor
The main function is not to allow repeated clicks. The main implementation is to assemble each call information into a key value and store it in redis. Each call obtains the key data from redis to verify the interval. The core code is as follows.
public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
{
String nowParams = "";
if (request instanceof RepeatedlyRequestWrapper)
{
RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
nowParams = HttpHelper.getBodyString(repeatedlyRequest);
}
// body参数为空,获取Parameter的数据
if (StringUtils.isEmpty(nowParams))
{
nowParams = JSONObject.toJSONString(request.getParameterMap());
}
Map<String, Object> nowDataMap = new HashMap<String, Object>();
nowDataMap.put(REPEAT_PARAMS, nowParams);
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
// 请求地址(作为存放cache的key值)
String url = request.getRequestURI();
// 唯一值(没有消息头则使用请求地址)
String submitKey = request.getHeader(header);
if (StringUtils.isEmpty(submitKey))
{
submitKey = url;
}
// 组装成加入redis的key值
String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey;
//根据key值查询redsi
Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
//如果能够查询到
if (sessionObj != null)
{
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
if (sessionMap.containsKey(url))
{
Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
//比对参数,同时比对时间
if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval()))
{
return true;
}
}
}
Map<String, Object> cacheMap = new HashMap<String, Object>();
cacheMap.put(url, nowDataMap);
redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
return false;
}
5.manager
The methods here AsyncManager、ShutdownManager
are provided for the asynchronous factory, and AsyncFactory is how to use asynchrony. If you need to use it, you can refer to it directly in the class.
6.security
1.JwtAuthenticationTokenFilter
Mainly to verify whether the token is correct,
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{
@Autowired
private TokenService tokenService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException
{
//验证用户信息
LoginUser loginUser = tokenService.getLoginUser(request);
if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
{
//刷新token
tokenService.verifyToken(loginUser);
//获取用户权限对象
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
//将用户权限等信息存放在SecurityContext中
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
chain.doFilter(request, response);
}
}
2.AuthenticationEntryPointImpl、LogoutSuccessHandlerImpl
Convert the call information to the fixed writing method returned by json. Refer to it if necessary.
7.web
1.server
Obtaining server information, such as cpu, etc., is written in a fixed way, if you need to refer to it, just copy it directly.
private void setCpuInfo(CentralProcessor processor)
{
// CPU信息
long[] prevTicks = processor.getSystemCpuLoadTicks();
Util.sleep(OSHI_WAIT_SECOND);
long[] ticks = processor.getSystemCpuLoadTicks();
long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
cpu.setCpuNum(processor.getLogicalProcessorCount());
cpu.setTotal(totalCpu);
cpu.setSys(cSys);
cpu.setUsed(user);
cpu.setWait(iowait);
cpu.setFree(idle);
}
/**
* 设置内存信息
*/
private void setMemInfo(GlobalMemory memory)
{
mem.setTotal(memory.getTotal());
mem.setUsed(memory.getTotal() - memory.getAvailable());
mem.setFree(memory.getAvailable());
}
.
.
.
2.exception
@RestControllerAdvice、@ExceptionHandler
Globally intercept exceptions. When there is an exception in the system, this class will directly obtain the exception and output it. Many classes do not need to try catch specially. A common way of writing architecture.
@RestControllerAdvice
public class GlobalExceptionHandler
{
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 权限校验异常
*/
@ExceptionHandler(AccessDeniedException.class)
public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage());
return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权");
}
/**
* 请求方式不支持
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
HttpServletRequest request)
{
String requestURI = request.getRequestURI();
log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
return AjaxResult.error(e.getMessage());
}
3.service
Permission-related services. Most of them are curd's business, here is the TokenService in detail.
1.TokenService
Among them, TokenService uses jwt to generate token, obtain data from token, and so on. Most of them are jwt fixed writing.
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map<String, Object> claims)
{
String token = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
return token;
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private Claims parseToken(String token)
{
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
6.ruoyi-admin
1.common general method
1.CaptchaController
Get Verification Code Generate a verification code through the API. The detailed code will not be explained.
2.CommonController
The general upload and download interface can be used directly if needed.
2. monitor monitoring
1. CacheController monitors redis
public class CacheController
{
@Autowired
private RedisTemplate<String, String> redisTemplate;
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping()
public AjaxResult getInfo() throws Exception
{
//redis的常用信息
Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
//rediskey数量
Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
Map<String, Object> result = new HashMap<>(3);
result.put("info", info);
result.put("dbSize", dbSize);
//key的详细信息
List<Map<String, String>> pieList = new ArrayList<>();
commandStats.stringPropertyNames().forEach(key -> {
Map<String, String> data = new HashMap<>(2);
String property = commandStats.getProperty(key);
data.put("name", StringUtils.removeStart(key, "cmdstat_"));
data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
pieList.add(data);
});
result.put("commandStats", pieList);
return AjaxResult.success(result);
}
}
2. ServerController server monitoring
It mainly monitors the information of the running server. The core code is as follows, if you need to use direct copy.
public void copyTo() throws Exception
{
SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
setCpuInfo(hal.getProcessor());
setMemInfo(hal.getMemory());
setSysInfo();
setJvmInfo();
setSysFiles(si.getOperatingSystem());
}
/**
* 设置CPU信息
*/
private void setCpuInfo(CentralProcessor processor)
{
// CPU信息
long[] prevTicks = processor.getSystemCpuLoadTicks();
Util.sleep(OSHI_WAIT_SECOND);
long[] ticks = processor.getSystemCpuLoadTicks();
long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
cpu.setCpuNum(processor.getLogicalProcessorCount());
cpu.setTotal(totalCpu);
cpu.setSys(cSys);
cpu.setUsed(user);
cpu.setWait(iowait);
cpu.setFree(idle);
}
/**
* 设置内存信息
*/
private void setMemInfo(GlobalMemory memory)
{
mem.setTotal(memory.getTotal());
mem.setUsed(memory.getTotal() - memory.getAvailable());
mem.setFree(memory.getAvailable());
}
/**
* 设置服务器信息
*/
private void setSysInfo()
{
Properties props = System.getProperties();
sys.setComputerName(IpUtils.getHostName());
sys.setComputerIp(IpUtils.getHostIp());
sys.setOsName(props.getProperty("os.name"));
sys.setOsArch(props.getProperty("os.arch"));
sys.setUserDir(props.getProperty("user.dir"));
}
/**
* 设置Java虚拟机
*/
private void setJvmInfo() throws UnknownHostException
{
Properties props = System.getProperties();
jvm.setTotal(Runtime.getRuntime().totalMemory());
jvm.setMax(Runtime.getRuntime().maxMemory());
jvm.setFree(Runtime.getRuntime().freeMemory());
jvm.setVersion(props.getProperty("java.version"));
jvm.setHome(props.getProperty("java.home"));
}
/**
* 设置磁盘信息
*/
private void setSysFiles(OperatingSystem os)
{
FileSystem fileSystem = os.getFileSystem();
List<OSFileStore> fsArray = fileSystem.getFileStores();
for (OSFileStore fs : fsArray)
{
long free = fs.getUsableSpace();
long total = fs.getTotalSpace();
long used = total - free;
SysFile sysFile = new SysFile();
sysFile.setDirName(fs.getMount());
sysFile.setSysTypeName(fs.getType());
sysFile.setTypeName(fs.getName());
sysFile.setTotal(convertFileSize(total));
sysFile.setFree(convertFileSize(free));
sysFile.setUsed(convertFileSize(used));
sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100));
sysFiles.add(sysFile);
}
}
3. SysLogininforController, SysOperlogController login log, operation log
Mainly query the log table generated by the previous AOP, and perform common additions, deletions, and modifications.
4. SysUserOnlineController online user management
The main functions are online user monitoring and kicking offline. This can be achieved by querying and deleting the redis cache.
3.system business code
Here are all system management business codes, and the writing method is relatively uniform, but there are some architectural regulations during the writing process, which will be explained one by one below.
1. @PreAuthorize("@ss.hasPermi('system:dict:list')")
Permission annotation, which has been explained in detail above
2.AjaxResult
Provides the return format of result encoding/call information/data, and provides a unified return format for the front desk. A fundamental component of the architecture.
public class AjaxResult extends HashMap<String, Object>
{
private static final long serialVersionUID = 1L;
/** 状态码 */
public static final String CODE_TAG = "code";
/** 返回内容 */
public static final String MSG_TAG = "msg";
/** 数据对象 */
public static final String DATA_TAG = "data";
/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public AjaxResult()
{
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public AjaxResult(int code, String msg)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}
/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
*/
public AjaxResult(int code, String msg, Object data)
{
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (StringUtils.isNotNull(data))
{
super.put(DATA_TAG, data);
}
}
/**
* 返回成功消息
*
* @return 成功消息
*/
public static AjaxResult success()
{
return AjaxResult.success("操作成功");
}
.
.
.
3.extends BaseController
As mentioned above BaseController
, if you use it here, you can directly call methods such as paging and sorting. Don't write every class.
Four. Summary
The ruoyi framework is easy to build, with very few dependent components. At the same time, it provides basic business functions, such as user management, department management, code generator, etc., but the depth of technology is still not in place, such as the use of mq, security framework and other technologies are not particularly involved.
But ruoyi is very friendly to the standardization and writing of the code, and the comments are also in place, the code is very clean and comfortable. This is awesome!
Therefore, it is highly recommended to use it as a private job and enterprise infrastructure. It would be even better if the extension function can be added reasonably.