Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save 303412768/fe04910d9c22a2f051e5127ec4a150d9 to your computer and use it in GitHub Desktop.
Save 303412768/fe04910d9c22a2f051e5127ec4a150d9 to your computer and use it in GitHub Desktop.
task
package com.player.location.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@Configuration
public class FastJsonHttpConverterConfig implements WebMvcConfigurer {
// fastjson配置
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Iterator<HttpMessageConverter<?>> iterator = converters.iterator();
while (iterator.hasNext()) {
HttpMessageConverter<?> converter = iterator.next();
if (converter instanceof MappingJackson2HttpMessageConverter) {
iterator.remove();
}
}
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(SerializerFeature.WriteNullListAsEmpty, // List类型字段为null时输出[]而非null
SerializerFeature.WriteMapNullValue, // 显示空字段
SerializerFeature.WriteNullStringAsEmpty, // 字符串类型字段为null时间输出""而非null
SerializerFeature.WriteNullBooleanAsFalse, // Boolean类型字段为null时输出false而null
SerializerFeature.PrettyFormat, // 美化json输出,否则会作为整行输出
SerializerFeature.WriteNullNumberAsZero, // 数值字段如果为null,输出为0,而非null
SerializerFeature.WriteNullBooleanAsFalse, // Boolean字段如果为null,输出为false,而非null
SerializerFeature.WriteDateUseDateFormat, // 时间格式yyyy-MM-dd HH: mm: ss
SerializerFeature.DisableCircularReferenceDetect); // 禁用循环引用检测
converter.setFastJsonConfig(config);
converters.add(converter);
List<MediaType> supportedMediaTypes = new ArrayList<>();
supportedMediaTypes.add(MediaType.APPLICATION_JSON);
supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML);
supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
supportedMediaTypes.add(MediaType.APPLICATION_PDF);
supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML);
supportedMediaTypes.add(MediaType.APPLICATION_XML);
supportedMediaTypes.add(MediaType.IMAGE_GIF);
supportedMediaTypes.add(MediaType.IMAGE_JPEG);
supportedMediaTypes.add(MediaType.IMAGE_PNG);
supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM);
supportedMediaTypes.add(MediaType.TEXT_HTML);
supportedMediaTypes.add(MediaType.TEXT_MARKDOWN);
supportedMediaTypes.add(MediaType.TEXT_PLAIN);
supportedMediaTypes.add(MediaType.TEXT_XML);
converter.setSupportedMediaTypes(supportedMediaTypes);
}
}
package com.player.location.controller;
import com.player.location.model.LocationInfo;
import com.player.location.model.Playground;
import com.player.location.service.IMoveStepService;
import com.player.location.tools.Result;
import com.player.location.tools.StaticInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/api/v1/order")
public class CalculateController {
@Autowired
public IMoveStepService moveStepService;
@PostMapping("/upload")
@ResponseBody
public Result playerMove(@RequestParam(value = "txt_file") MultipartFile files,HttpServletRequest request) {
Result result=moveStepService.saveFile(files, request);
result = moveStepService.readFileByLine(result.object.toString());
result =moveStepService.move((List<String>) result.object);
return result;
}
}
package com.player.location;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LocationApplication {
public static void main(String[] args) {
SpringApplication.run(LocationApplication.class, args);
}
}
package com.player.location.model;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Data
@Getter
@Setter
public class LocationInfo {
public int x;
public int y;
public String toward;
public int index;
public List<String> orderList;
}
package com.player.location.model;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Playground {
public int maxX=0;
public int maxY=0;
}
package com.player.location.service;
import com.player.location.model.LocationInfo;
import com.player.location.model.Playground;
import com.player.location.tools.Result;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
public interface IMoveStepService {
//init size for playground
// String initPlayground(int x, int y);
//
// Result initPlayerLocation(Playground playground, LocationInfo locationInfo);
Result move(List<String> orderList);
Result saveFile(MultipartFile files, HttpServletRequest request);
Result readFileByLine(String filePath);
}
package com.player.location.service;
import com.player.location.model.LocationInfo;
import com.player.location.model.Playground;
import com.player.location.tools.Result;
import com.player.location.tools.StaticInfo;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
@Service
public class MoveStepService implements IMoveStepService {
@Override
public Result move(List<String> orderList) {
Playground playground = getPlayground(orderList.get(0));
if (null == playground) {
return Result.error(null, "Data Error on line one!");
}
List<LocationInfo> infos = findAllStatPointAndOrder(orderList);
beginTowardAndMove(infos);
for (LocationInfo info : infos) {
if (info.getX() > playground.getMaxX() || info.getY() > playground.getMaxY()) {
return Result.error(null, StaticInfo.ERROR_MSG_OVER_BORDER);
}
}
return Result.ok(infos);
}
@Override
public Result saveFile(MultipartFile files, HttpServletRequest request) {
String sourceName = files.getOriginalFilename(); // 原始文件名
String fileType = sourceName.substring(sourceName.lastIndexOf("."));
if (files.isEmpty() || StringUtils.isBlank(fileType)) {
return Result.error(null, "File is none");
}
String filename= RandomStringUtils.randomAlphanumeric(10)+"."+fileType;
// Get temp path
// for example /wabapp/upload/xxx.txt
String base = request.getSession().getServletContext().getRealPath("/upload");
File file = new File(base);
if (!file.exists()) {
file.mkdirs();
}
// upload file
String path = base + File.separator + filename;
File upload = new File(path);
try {
files.transferTo(upload);
} catch (IOException e) {
return Result.error(null, "There are some errors during upload");
}
return Result.ok(path);
}
@Override
public Result readFileByLine(String filePath) {
String lineText;
List<String> list = new ArrayList<>();
//*** Read file by line ***
File file = new File(filePath);
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
while ((lineText = br.readLine()) != null) {
//When current line is empty, skip this line
if (lineText.trim().length() == 0) {
continue;
}
list.add(lineText.trim());
}
} catch (IOException e) {
e.printStackTrace();
file.delete();
return Result.error(list,"Read file error");
}
file.delete();
return Result.ok(list);
}
/**
* 设置整个场地大小,后期会校验是否越界
* @param str
* @return
*/
private Playground getPlayground(String str) {
String[] pgArr = str.split("\\s+");
if (StringUtils.isNumeric(pgArr[0]) && StringUtils.isNumeric(pgArr[1])) {
Playground playground = new Playground();
playground.setMaxX(Integer.parseInt(pgArr[0]));
playground.setMaxY(Integer.parseInt(pgArr[1]));
return playground;
}
return null;
}
public static String allChars = "LMR";
/**
* 验证指令是否有效
*
* @param str
* @return
*/
public static Boolean vailOrder(String str) {
//将字符串转化为字符数组
char[] chars = str.toCharArray();
//定义一个字符串c,循环遍历遍历chars数组
for (char c : chars) {
Boolean isInclude = allChars.contains(Character.toString(c));
if (!isInclude) {
return false;
}
}
return true;
}
/**
* 查询所有人的起始点以及对于的移动指令
*
* @param stringList 所有的指令合集
* @return
*/
private List<LocationInfo> findAllStatPointAndOrder(List<String> stringList) {
List<LocationInfo> locationInfos = new ArrayList<>();
for (String str : stringList) {
String[] arr = str.split("\\s+");
//排除初始化数据
if (arr.length == 2) {
continue;
}
//判定每个人的起始点
if (StringUtils.isNumeric(arr[0]) && StringUtils.isNumeric(arr[1]) && StaticInfo.DIRECTIONS.contains(arr[2]) && arr.length == 3) {
LocationInfo locationInfo = new LocationInfo();
locationInfo.setX(Integer.parseInt(arr[0]));
locationInfo.setY(Integer.parseInt(arr[1]));
locationInfo.setToward(arr[2].trim().toUpperCase());
locationInfos.add(locationInfo);
} else {
//解析移动命令并存储到对于人的数据中
if (vailOrder(str)) {
LocationInfo info = locationInfos.get(locationInfos.size() - 1);
List<String> orders;
if (info.getOrderList() == null) {
orders = new ArrayList<>();
} else {
orders = info.getOrderList();
}
orders.add(str);
info.setOrderList(orders);
}
}
}
return locationInfos;
}
private static String[] towardArr = {"W", "N", "E", "S"};
/**
* 移动与方向逻辑
* @param infos
*/
public void beginTowardAndMove(List<LocationInfo> infos) {
for (LocationInfo locationInfo : infos) {
for (String str : locationInfo.getOrderList()) {
char[] chars = str.toCharArray();
for (char c : chars) {
String nexStep = Character.toString(c).toUpperCase();
switch (nexStep) {
case "L":
case "R":
locationInfo.setToward(getNextToward(locationInfo.getToward(), nexStep));
break;
case "M":
moveByOrder(locationInfo);
break;
}
}
}
}
}
/**
* 方向处理
* @param currentToward
* @param nextToward
* @return
*/
public String getNextToward(String currentToward, String nextToward) {
String newToward = currentToward;
for (int i = 0; i < towardArr.length; i++) {
if (towardArr[i].equals(currentToward)) {
switch (nextToward) {
case "L":
if (i == 0) {
newToward = towardArr[3];
} else {
newToward = towardArr[i - 1];
}
break;
case "R":
if (i == 3) {
newToward = towardArr[0];
} else {
newToward = towardArr[i + 1];
}
break;
}
}
}
return newToward;
}
/**
* 移动逻辑
* @param info
*/
public void moveByOrder(LocationInfo info) {
String toward = info.getToward();
int x = info.getX();
int y = info.getY();
switch (toward.toUpperCase()) {
case "W" -> x = x - 1;
case "E" -> x = x + 1;
case "N" -> y = y + 1;
case "S" -> y = y - 1;
}
info.setX(x);
info.setY(y);
}
}
package com.player.location.tools;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Result {
public Result() {
}
public Result(Object object, int code, String msg) {
this.object = object;
this.code = code;
this.msg = msg;
}
public Object object;
public int code;
public String msg;
public static Result ok(Object object) {
Result result = new Result(object, StaticInfo.ok, null);
return result;
}
public static Result error(Object object,String msg) {
Result result = new Result(object, StaticInfo.error, msg);
return result;
}
}
package com.player.location.tools;
public class StaticInfo {
public static String ERROR_MSG_OVER_BORDER = "Over the border!";
public static int ok = 200;
public static int error = 0;
public static String DIRECTIONS = "NSEW";
}
server:
port: 80
spring:
jackson:
property-naming-strategy: UPPER_CAMEL_CASE
serialization:
indent-output: true
<html>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.16.0/dist/bootstrap-table.min.css">
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css">
<title>Re-located for player</title>
</head>
<body>
<div class="container-fluid">
<div class="row" style="padding-top: 10px;padding-bottom: 10px;">
<div class="col-sm">
<form enctype="multipart/form-data">
<p>上传txt文件<input type="file" id="txt_file" name="txt_file"/>
<button id="import" type="button" class="btn btn-primary">导入</button>
</p>
</form>
</div>
</div>
<div class="row" id="result">
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"
integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI"
crossorigin="anonymous"></script>
<script src="https://unpkg.com/bootstrap-table@1.16.0/dist/bootstrap-table.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/toastify-js"></script>
<script src="http://malsup.github.com/jquery.form.js"></script>
<script type="text/javascript">
/**
* Show Alert Information
* */
function showToast(text) {
Toastify({
text: text,
duration: 3000,
newWindow: true,
close: true,
gravity: "top", // `top` or `bottom`
position: 'left', // `left`, `center` or `right`
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
stopOnFocus: true, // Prevents dismissing of toast on hover
}).showToast();
}
/**
* upload files
*/
$("#import").click(function () {
let files = $('#txt_file').prop('files');
let data = new FormData();
data.append('txt_file', files[0]);
$.ajax({
url: "./api/v1/order/upload",
type: 'POST',
data: data,
cache: false,
processData: false,
contentType: false,
//success: dealWithData(data),
}).done(function (data) {
if (data.code === 200) {
let html = "";
$.each(data.object, function (n, value) {
html += "<div class=\"alert alert-primary\" role=\"alert\">\n" +
value.x + " " + value.y + " " + value.toward +
"</div>"+"&nbsp;&nbsp;"
});
$("#result").html(html);
} else {
showToast(data.msg)
}
});
});
</script>
</body>
</html>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel"> Initial Location</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<input type="text" id="first_rows" class="form-control" placeholder="First Rows">
</div>
<div class="form-group">
<input type="text" id="first_cells" class="form-control" placeholder="First Cells">
</div>
<div class="form-group">
<select id="toward" class="custom-select" >
<option value="W" selected>West</option>
<option value="N">North</option>
<option value="E">East</option>
<option value="S">South</option>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="setUpLocation()">Submit</button>
</div>
</div>
<script type="text/javascript">
function setUpLocation() {
console.log($("#toward").val());
let locationInfo = {
'row': $("#first_rows").val(),
'cell': $("#first_cells").val(),
'toward':$("#toward").val()
};
const post_url = "./api/v1/order/location"; //get form action url
$.post(post_url, locationInfo, function (data) {
console.log(data.code);
if (data.code == 200) {
$('#myModal').modal('hide');
} else {
showToast(data.msg)
}
});
}
</script>
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel"> Initial Playground</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<input type="text" name="maxRows" id="init_rows" class="form-control" placeholder="Init Rows">
</div>
<div class="form-group">
<input type="text" name="maxCells" id="init_cells" class="form-control" placeholder="Init Cells">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="initPlayground()">Submit</button>
</div>
</div>
<script type="text/javascript">
function initPlayground() {
init_rows = $("#init_rows").val();
init_cells = $("#init_cells").val();
let playgroundJson = {
'maxRows': init_rows,
'maxCells': init_cells
};
const post_url = "./api/v1/order/init"; //get form action url
$.post(post_url, playgroundJson, function (data) {
if (data.code === 200) {
buildTable($table, init_cells, init_rows);
$('#myModal').modal('hide');
} else {
showToast("There are some errors! Please reload the website.")
}
});
}
</script>
package com.player.location;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class LocationApplicationTests {
@Test
void contextLoads() {
}
}
@303412768
Copy link
Author

init

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment