screen-manage/src/main/java/com/moral/api/controller/CruiserController.java
New file @@ -0,0 +1,80 @@ package com.moral.api.controller; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.moral.api.entity.ManageCoordinate; import com.moral.api.entity.SpecialDevice; import com.moral.api.pojo.dto.cruiser.CruiserDTO; import com.moral.api.service.HistorySecondCruiserService; import com.moral.api.service.ManageCoordinateService; import com.moral.constant.ResponseCodeEnum; import com.moral.constant.ResultMessage; import com.moral.util.WebUtils; @Slf4j @Api(tags = {"走航车路段查询"}) @RestController @RequestMapping("cruiserInfo") public class CruiserController { @Autowired private HistorySecondCruiserService historySecondCruiserService; /** * * @return */ @GetMapping("selectCruisers") @ApiOperation(value = "获取所有走航车") public ResultMessage selectCruisers() { List<SpecialDevice> specialDevices = historySecondCruiserService.selectCruisers(); if (ObjectUtils.isEmpty(specialDevices)){ return ResultMessage.fail(ResponseCodeEnum.TARGET_IS_NULL.getCode(), ResponseCodeEnum.TARGET_IS_NULL.getMsg()); } return ResultMessage.ok(specialDevices); } @GetMapping("getCruiserInFo") @ApiOperation(value = "走航车轨迹", notes = "走航车轨迹") @ApiImplicitParams(value = { @ApiImplicitParam(name = "token", value = "token", required = true, paramType = "header", dataType = "String"), @ApiImplicitParam(name = "mac", value = "设备mac", required = true, paramType = "query", dataType = "String"), @ApiImplicitParam(name = "time1", value = "时间,2021-08-18", required = true, paramType = "query", dataType = "String"), @ApiImplicitParam(name = "time2", value = "时间,2021-08-18", required = true, paramType = "query", dataType = "String") }) public ResultMessage getCruiserInFo(HttpServletRequest request){ Map<String, Object> params = WebUtils.getParametersStartingWith(request, null); if (!params.containsKey("mac") || !params.containsKey("time1")|| !params.containsKey("time2")) { return ResultMessage.fail(ResponseCodeEnum.PARAMETERS_IS_MISSING.getCode(), ResponseCodeEnum.PARAMETERS_IS_MISSING.getMsg()); } List<CruiserDTO> data = historySecondCruiserService.getCruiserInFo(params); return ObjectUtils.isEmpty(data)? ResultMessage.ok() : ResultMessage.ok(data); } } screen-manage/src/main/java/com/moral/api/controller/ManageCoordinateController.java
New file @@ -0,0 +1,98 @@ package com.moral.api.controller; import io.swagger.annotations.Api; import javafx.scene.input.Mnemonic; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.annotations.Update; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.moral.api.entity.ManageCoordinate; import com.moral.api.service.ManageCoordinateService; import com.moral.constant.ResponseCodeEnum; import com.moral.constant.ResultMessage; @Slf4j @RestController @Api(tags = {"添加路段模块"}) @RequestMapping("coordinate") @CrossOrigin(origins = "*", maxAge = 3600) public class ManageCoordinateController { @Autowired private ManageCoordinateService manageCoordinateService; /** * 添加路段信息 * @param params * @return */ @PostMapping("interCruiserRoad") public ResultMessage interCruiserRoad(@RequestBody Map<String,Object> params){ if (!params.containsKey("startPoint") || !params.containsKey("endPoint")) { return ResultMessage.fail(ResponseCodeEnum.PARAMETERS_IS_MISSING.getCode(), ResponseCodeEnum.PARAMETERS_IS_MISSING.getMsg()); } Integer integer = manageCoordinateService.interCoordinate(params); if (integer==null){ return ResultMessage.ok("路段已存在"); } return ResultMessage.ok(); } /** * 修改路段信息 * @param manageCoordinate * @return */ @PostMapping("updateCruiserRoad") public ResultMessage updateCruiserRoad(@RequestBody ManageCoordinate manageCoordinate){ if (ObjectUtils.isEmpty(manageCoordinate)){ return ResultMessage.fail(ResponseCodeEnum.PARAMETERS_IS_MISSING.getCode(), ResponseCodeEnum.PARAMETERS_IS_MISSING.getMsg()); } manageCoordinateService.updateCoordinate(manageCoordinate); return ResultMessage.ok(); } /** * 删除路段信息 * @param id * @return */ @GetMapping("deleteCruiserRoad") public ResultMessage deleteCruiser(Integer id){ if (id==null){ return ResultMessage.fail(ResponseCodeEnum.PARAMETERS_IS_MISSING.getCode(), ResponseCodeEnum.PARAMETERS_IS_MISSING.getMsg()); } manageCoordinateService.deleteCoordinate(id); return ResultMessage.ok(); } /** * 查询路段信息 * * @return */ @GetMapping("selectCruiserRoad") public ResultMessage selectCruiser(){ List<ManageCoordinate> manageCoordinates = manageCoordinateService.selectCoordinate(); if (ObjectUtils.isEmpty(manageCoordinates)){ return ResultMessage.fail(ResponseCodeEnum.TARGET_IS_NULL.getCode(), ResponseCodeEnum.TARGET_IS_NULL.getMsg()); } return ResultMessage.ok(manageCoordinates); } } screen-manage/src/main/java/com/moral/api/controller/ManageCoordinateDetailController.java
New file @@ -0,0 +1,90 @@ package com.moral.api.controller; import io.swagger.annotations.Api; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.moral.api.entity.ManageCoordinateDetail; import com.moral.api.service.ManageCoordinateDetailService; import com.moral.constant.ResponseCodeEnum; import com.moral.constant.ResultMessage; @Slf4j @RestController @Api(tags = {"添加经纬度模块"}) @RequestMapping("coordinateDetail") public class ManageCoordinateDetailController { @Autowired private ManageCoordinateDetailService manageCoordinateDetailService; /** * 新增经纬度点 * @param manageCoordinateDetail * @return */ @PostMapping("insert") public ResultMessage insert(@RequestBody ManageCoordinateDetail manageCoordinateDetail){ if (ObjectUtils.isEmpty(manageCoordinateDetail)){ return ResultMessage.fail(ResponseCodeEnum.PARAMETERS_IS_MISSING.getCode(), ResponseCodeEnum.PARAMETERS_IS_MISSING.getMsg()); } Integer integer = manageCoordinateDetailService.insertCoordinate(manageCoordinateDetail); if (integer==null){ return ResultMessage.ok("经纬度已存在"); } return ResultMessage.ok(); } /** * 批量新增 * @return */ @PostMapping("batch") public ResultMessage getInserts(){ return null; } /** * 修改经纬度点 * @param manageCoordinateDetail * @return */ @PostMapping("update") public ResultMessage update(@RequestBody ManageCoordinateDetail manageCoordinateDetail){ return null; } /** * 删除经纬度点 * @param id * @return */ @GetMapping("delete") public ResultMessage delete(Integer id){ if (id==null){ return ResultMessage.fail(ResponseCodeEnum.PARAMETERS_IS_MISSING.getCode(), ResponseCodeEnum.PARAMETERS_IS_MISSING.getMsg()); } manageCoordinateDetailService.deleteCoordinate(id); return ResultMessage.ok(); } /** * 查询坐标点 * @return */ @GetMapping("select") public ResultMessage selectAll(){ return null; } } screen-manage/src/main/java/com/moral/api/entity/ManageCoordinate.java
New file @@ -0,0 +1,57 @@ package com.moral.api.entity; import lombok.Data; import lombok.EqualsAndHashCode; import java.util.Date; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.extension.activerecord.Model; /** * 走航路段表 */ @Data @EqualsAndHashCode(callSuper = false) public class ManageCoordinate extends Model<ManageCoordinate> { private static final long serialVersionUID = 1L; /** * 路段id */ @TableId(value = "coordinate_id", type = IdType.AUTO) private Integer coordinateId; /** * 起点名称 */ private String startPoint; /** * 终点名称 */ private String endPoint; /** *是否删除 */ private Integer isDel; /** * 创建时间 */ private Date createTime; /** * 修改时间 */ private Date updateTime; /** * 修改人id * */ private Integer updateUserId; /** * 修改人名称 */ private String updayeUserName; } screen-manage/src/main/java/com/moral/api/entity/ManageCoordinateDetail.java
New file @@ -0,0 +1,58 @@ package com.moral.api.entity; import lombok.Data; import lombok.EqualsAndHashCode; import java.util.Date; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.extension.activerecord.Model; @Data @EqualsAndHashCode(callSuper = false) public class ManageCoordinateDetail extends Model<ManageCoordinateDetail> { private static final long serialVersionUID = 1L; /** * 经纬度id */ @TableId(value = "id", type = IdType.AUTO) private Integer id; /** * 路段id */ private Integer coordinateId; /** * 经度 */ private Double longitude; /** *纬度 */ private Double latitude; /** * 创建时间 */ private Date createTime; /** * 修改时间 */ private Date updateTime; /** * 修改人id * */ private Integer updateUserId; /** * 修改人名称 */ private String updayeUserName; } screen-manage/src/main/java/com/moral/api/mapper/HistorySecondCruiserMapper.java
@@ -1,7 +1,11 @@ package com.moral.api.mapper; import java.util.List; import java.util.Map; import com.moral.api.entity.HistorySecondCruiser; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.moral.api.pojo.dto.cruiser.CruiserDTO; /** * <p> @@ -13,4 +17,6 @@ */ public interface HistorySecondCruiserMapper extends BaseMapper<HistorySecondCruiser> { List<CruiserDTO> getCruiserInfo(Map<String,Object> params); } screen-manage/src/main/java/com/moral/api/mapper/ManageCoordinateDetailMapper.java
New file @@ -0,0 +1,7 @@ package com.moral.api.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.moral.api.entity.ManageCoordinateDetail; public interface ManageCoordinateDetailMapper extends BaseMapper<ManageCoordinateDetail> { } screen-manage/src/main/java/com/moral/api/mapper/ManageCoordinateMapper.java
New file @@ -0,0 +1,8 @@ package com.moral.api.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.moral.api.entity.ManageCoordinate; public interface ManageCoordinateMapper extends BaseMapper<ManageCoordinate> { } screen-manage/src/main/java/com/moral/api/pojo/dto/cruiser/CruiserDTO.java
New file @@ -0,0 +1,46 @@ package com.moral.api.pojo.dto.cruiser; import lombok.Data; import java.util.Objects; import com.fasterxml.jackson.annotation.JsonProperty; @Data public class CruiserDTO { /** * 数据时间 */ private String time; /** * 纬度 */ @JsonProperty(value = "flylat") private Double flyLat; /** * 经度 */ @JsonProperty(value = "flylon") private Double flyLon; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CruiserDTO cruiser = (CruiserDTO) o; //当type、color 内容都相等的时候,才返回true return Objects.equals(flyLat, cruiser.flyLat) && Objects.equals(flyLon, cruiser.flyLon); } @Override public int hashCode() { return Objects.hash(flyLat, flyLon); } } screen-manage/src/main/java/com/moral/api/service/HistorySecondCruiserService.java
@@ -2,7 +2,10 @@ import com.moral.api.entity.HistorySecondCruiser; import com.baomidou.mybatisplus.extension.service.IService; import com.moral.api.entity.SpecialDevice; import com.moral.api.pojo.dto.cruiser.CruiserDTO; import java.util.List; import java.util.Map; /** @@ -18,4 +21,9 @@ //秒数据insert void insertHistorySecond(Map<String, Object> data); //获取所有走航车 List<SpecialDevice> selectCruisers(); //查询走航车轨迹 List<CruiserDTO> getCruiserInFo(Map<String, Object> params); } screen-manage/src/main/java/com/moral/api/service/ManageCoordinateDetailService.java
New file @@ -0,0 +1,13 @@ package com.moral.api.service; import com.baomidou.mybatisplus.extension.service.IService; import com.moral.api.entity.ManageCoordinateDetail; public interface ManageCoordinateDetailService extends IService<ManageCoordinateDetail> { Integer insertCoordinate(ManageCoordinateDetail manageCoordinateDetail); void deleteCoordinate(Integer id); } screen-manage/src/main/java/com/moral/api/service/ManageCoordinateService.java
New file @@ -0,0 +1,26 @@ package com.moral.api.service; import java.util.List; import java.util.Map; import com.baomidou.mybatisplus.extension.service.IService; import com.moral.api.entity.ManageCoordinate; public interface ManageCoordinateService extends IService<ManageCoordinate> { /** * 添加路段信息 * @param params * @return */ Integer interCoordinate(Map<String,Object> params); void updateCoordinate(ManageCoordinate manageCoordinate); void deleteCoordinate(Integer id); List<ManageCoordinate> selectCoordinate(); } screen-manage/src/main/java/com/moral/api/service/impl/HistorySecondCruiserServiceImpl.java
@@ -1,10 +1,13 @@ package com.moral.api.service.impl; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.moral.api.entity.HistorySecondCruiser; import com.moral.api.entity.Sensor; import com.moral.api.entity.SpecialDevice; import com.moral.api.mapper.HistorySecondCruiserMapper; import com.moral.api.mapper.SpecialDeviceMapper; import com.moral.api.pojo.dto.cruiser.CruiserDTO; import com.moral.api.service.DeviceService; import com.moral.api.service.HistorySecondCruiserService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; @@ -12,10 +15,15 @@ import com.moral.constant.Constants; import com.moral.constant.RedisConstants; import com.moral.util.DateUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import java.sql.Wrapper; import java.util.Date; import java.util.List; import java.util.Map; @@ -29,6 +37,7 @@ * @author moral * @since 2021-09-02 */ @Slf4j @Service public class HistorySecondCruiserServiceImpl extends ServiceImpl<HistorySecondCruiserMapper, HistorySecondCruiser> implements HistorySecondCruiserService { @@ -37,6 +46,8 @@ @Autowired private SpecialDeviceService specialDeviceService; @Autowired private SpecialDeviceMapper specialDeviceMapper; @Autowired private RedisTemplate redisTemplate; @@ -78,4 +89,45 @@ historySecondCruiser.setBatch(batchTime); historySecondCruiserMapper.insert(historySecondCruiser); } /** * 获取所有走航车信息 * @return */ @Override public List<SpecialDevice> selectCruisers() { QueryWrapper<SpecialDevice> wrapper = new QueryWrapper<>(); wrapper.eq("is_delete",Constants.NOT_DELETE); List<SpecialDevice> specialDevices = specialDeviceMapper.selectList(wrapper); return specialDevices; } /** * 查看走航车轨迹 * @param params * @return */ @Override public List<CruiserDTO> getCruiserInFo(Map<String, Object> params) { params.put("dateFormat", "%Y-%m-%d %H:%i:%s"); List<CruiserDTO> data = historySecondCruiserMapper.getCruiserInfo(params); List<CruiserDTO> rsCruiser = data.stream().distinct().collect(Collectors.toList()); rsCruiser.removeIf(o->{ if (ObjectUtils.isEmpty(o.getFlyLon()) || ObjectUtils.isEmpty(o.getFlyLat())) { return true; } double lon = o.getFlyLon(); double lat = o.getFlyLat(); if (lon < 70 || lon > 150 || lat < 20 || lat > 60) { return true; } return false; }); if(CollectionUtils.isEmpty(data)){ return null; } log.info(data.size()+""); log.info(rsCruiser.size()+""); return rsCruiser; } } screen-manage/src/main/java/com/moral/api/service/impl/ManageCoordinateDetailServiceImpl.java
New file @@ -0,0 +1,50 @@ package com.moral.api.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.moral.api.entity.ManageCoordinateDetail; import com.moral.api.mapper.ManageCoordinateDetailMapper; import com.moral.api.service.ManageCoordinateDetailService; @Service public class ManageCoordinateDetailServiceImpl extends ServiceImpl<ManageCoordinateDetailMapper, ManageCoordinateDetail> implements ManageCoordinateDetailService { @Autowired private ManageCoordinateDetailMapper manageCoordinateDetailMapper; /** * 新增经纬度 * @param manageCoordinateDetail * @return */ @Override public Integer insertCoordinate(ManageCoordinateDetail manageCoordinateDetail) { QueryWrapper<ManageCoordinateDetail> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("coordinate_id",manageCoordinateDetail.getCoordinateId()); queryWrapper.eq("longitude",manageCoordinateDetail.getLongitude()); queryWrapper.eq("latitude",manageCoordinateDetail.getLatitude()); Integer integer = manageCoordinateDetailMapper.selectCount(queryWrapper); if (integer<1){ manageCoordinateDetail.setCreateTime(new Date()); manageCoordinateDetail.setUpdateTime(new Date()); int insert = manageCoordinateDetailMapper.insert(manageCoordinateDetail); return insert; } return null; } /** * 删除经纬度点 * @param id */ @Override public void deleteCoordinate(Integer id) { manageCoordinateDetailMapper.deleteById(id); } } screen-manage/src/main/java/com/moral/api/service/impl/ManageCoordinateServiceImpl.java
New file @@ -0,0 +1,81 @@ package com.moral.api.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; import java.util.List; import java.util.Map; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.moral.api.entity.ManageCoordinate; import com.moral.api.mapper.ManageCoordinateMapper; import com.moral.api.service.ManageCoordinateService; @Service public class ManageCoordinateServiceImpl extends ServiceImpl<ManageCoordinateMapper, ManageCoordinate> implements ManageCoordinateService { @Autowired private ManageCoordinateMapper manageCoordinateMapper; /** * 新增路段 * @param params * @return */ @Override public Integer interCoordinate(Map<String, Object> params) { String startPoint = params.get("startPoint").toString(); String endPoint = params.get("endPoint").toString(); QueryWrapper<ManageCoordinate> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("start_point",startPoint); queryWrapper.eq("end_point",endPoint); Integer integer = manageCoordinateMapper.selectCount(queryWrapper); if (integer>=1){ return null; } ManageCoordinate manageCoordinate = new ManageCoordinate(); manageCoordinate.setCreateTime(new Date()); manageCoordinate.setUpdateTime(new Date()); manageCoordinate.setStartPoint(startPoint); manageCoordinate.setEndPoint(endPoint); manageCoordinate.setIsDel(0); int code = manageCoordinateMapper.insert(manageCoordinate); return code; } /** * 修改路段 * @param manageCoordinate */ @Override public void updateCoordinate(ManageCoordinate manageCoordinate) { manageCoordinate.setUpdateTime(new Date()); manageCoordinateMapper.updateById(manageCoordinate); } /** * 删除路段 * @param id */ @Override public void deleteCoordinate(Integer id) { manageCoordinateMapper.deleteById(id); } /** * 查询路段信息 * @return */ @Override public List<ManageCoordinate> selectCoordinate() { QueryWrapper<ManageCoordinate> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("is_del",0); List<ManageCoordinate> manageCoordinates = manageCoordinateMapper.selectList(queryWrapper); return manageCoordinates; } } screen-manage/src/main/resources/mapper/HistorySecondCruiserMapper.xml
@@ -11,4 +11,13 @@ <result column="batch" property="batch" /> </resultMap> <select id="getCruiserInfo" resultType="com.moral.api.pojo.dto.cruiser.CruiserDTO"> select DATE_FORMAT(`time`, #{dateFormat}) AS time,value ->>'$.flylat' as flyLat,value ->>'$.flylon' as flyLon from history_second_cruiser WHERE mac = #{mac} AND `time` <![CDATA[>=]]> #{time1} AND `time` <![CDATA[<=]]> #{time2} order by time </select> </mapper> screen-manage/src/main/resources/mapper/ManageCoordinateDetailMapper.xml
New file @@ -0,0 +1,18 @@ <?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.moral.api.mapper.ManageCoordinateDetailMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="com.moral.api.entity.ManageCoordinateDetail"> <id column="id" property="id" /> <result column="coordinate_id" property="coordinateId" /> <result column="longitude" property="longitude" /> <result column="latitude" property="latitude" /> <result column="create_time" property="createTime" /> <result column="update_time" property="updateTime" /> <result column="update_user_id" property="updateUserId" /> <result column="updaye_user_name" property="updayeUserName" /> </resultMap> </mapper> screen-manage/src/main/resources/mapper/ManageCoordinateMapper.xml
New file @@ -0,0 +1,18 @@ <?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.moral.api.mapper.ManageCoordinateMapper"> <!-- 通用查询映射结果 --> <resultMap id="BaseResultMap" type="com.moral.api.entity.ManageCoordinate"> <id column="coordinate_id" property="coordinateId" /> <result column="start_point" property="startPoint" /> <result column="end_point" property="endPoint" /> <result column="is_del" property="isDel" /> <result column="create_time" property="createTime" /> <result column="update_time" property="updateTime" /> <result column="update_user_id" property="updateUserId" /> <result column="updaye_user_name" property="updayeUserName" /> </resultMap> </mapper>